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.

4130 lines
118 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. dbsecret.c
  5. Abstract:
  6. LSA - Database - Secret Object Private API Workers
  7. NOTE: This module should remain as portable code that is independent
  8. of the implementation of the LSA Database. As such, it is
  9. permitted to use only the exported LSA Database interfaces
  10. contained in db.h and NOT the private implementation
  11. dependent functions in dbp.h.
  12. Author:
  13. Scott Birrell (ScottBi) December 12, 1991
  14. Environment:
  15. Revision History:
  16. --*/
  17. #include <lsapch2.h>
  18. #include "dbp.h"
  19. #include <lmcons.h> // CRYPT_TXT_LEN
  20. #include <crypt.h> // required for logonmsv.h
  21. #include <logonmsv.h> // SSI_SECRET_NAME
  22. #include <kerberos.h> // KERB_CHANGE_MACH_PWD_REQUEST
  23. #include <ntddnfs.h> // DD_NFS_DEVICE_NAME_U
  24. #include <remboot.h> // LMMR_RI_XXX
  25. #include <lsawmi.h>
  26. #if defined(REMOTE_BOOT)
  27. //
  28. // This BOOLEAN tracks whether we have received the first LsarQuerySecret()
  29. // call for the the machine account secret. On the first call, we check
  30. // with the remote boot code to see if the password has changed while
  31. // the machine was off.
  32. //
  33. static BOOLEAN FirstMachineAccountQueryDone = FALSE;
  34. #endif // defined(REMOTE_BOOT)
  35. //
  36. // The name of the machine account password secret.
  37. //
  38. static UNICODE_STRING LsapMachineSecret = { sizeof(SSI_SECRET_NAME)-sizeof(WCHAR), sizeof(SSI_SECRET_NAME), SSI_SECRET_NAME};
  39. VOID
  40. LsaIFree_LSAI_SECRET_ENUM_BUFFER (
  41. IN PVOID Buffer,
  42. IN ULONG Count
  43. );
  44. //
  45. // The real function that LsarSetSecret() calls.
  46. //
  47. NTSTATUS
  48. LsapDbSetSecret(
  49. IN LSAPR_HANDLE SecretHandle,
  50. IN OPTIONAL PLSAPR_CR_CIPHER_VALUE CipherCurrentValue,
  51. IN OPTIONAL PLARGE_INTEGER CurrentTime,
  52. IN OPTIONAL PLSAPR_CR_CIPHER_VALUE CipherOldValue,
  53. IN OPTIONAL PLARGE_INTEGER OldTime
  54. #if defined(REMOTE_BOOT)
  55. ,
  56. IN BOOLEAN RemoteBootMachinePasswordChange
  57. #endif // defined(REMOTE_BOOT)
  58. );
  59. BOOLEAN
  60. LsapDbSecretIsMachineAcc(
  61. IN LSAPR_HANDLE SecretHandle
  62. )
  63. /*++
  64. Routine Description:
  65. This function determines if the given handle refers to the local machine account
  66. Arguments:
  67. SecretHandle - Handle from an LsaOpenSecret call.
  68. Return Values:
  69. TRUE -- The handle refers to the machine account
  70. FALSE -- It doesn't
  71. --*/
  72. {
  73. BOOLEAN IsMachAcc = FALSE;
  74. UNICODE_STRING CheckSecret;
  75. LSAP_DB_HANDLE Handle = ( LSAP_DB_HANDLE )SecretHandle;
  76. RtlInitUnicodeString( &CheckSecret, L"$MACHINE.ACC" );
  77. if ( RtlEqualUnicodeString( &CheckSecret, &Handle->LogicalNameU, TRUE ) ) {
  78. IsMachAcc = TRUE;
  79. }
  80. return( IsMachAcc );
  81. }
  82. NTSTATUS
  83. LsarCreateSecret(
  84. IN LSAPR_HANDLE PolicyHandle,
  85. IN PLSAPR_UNICODE_STRING SecretName,
  86. IN ACCESS_MASK DesiredAccess,
  87. OUT PLSAPR_HANDLE SecretHandle
  88. )
  89. /*++
  90. Routine Description:
  91. This function is the LSA server RPC worker routine for the
  92. LsaCreateSecret API.
  93. The LsaCreateSecret API creates a named Secret object in the
  94. Lsa Database. Each Secret Object can have two values assigned,
  95. called the Current Value and the Old Value. The meaning of these
  96. values is known to the Secret object creator. The caller must have
  97. LSA_CREATE_SECRET access to the LsaDatabase object.
  98. Arguments:
  99. PolicyHandle - Handle from an LsaOpenPolicy call.
  100. SecretName - Pointer to Unicode String specifying the name of the
  101. secret.
  102. DesiredAccess - Specifies the accesses to be granted to the newly
  103. created and opened secret.
  104. SecretHandle - Receives a handle to the newly created and opened
  105. Secret object. This handle is used on subsequent accesses to
  106. the object until closed.
  107. Return Values:
  108. NTSTATUS - Standard Nt Result Code
  109. STATUS_ACCESS_DENIED - Caller does not have the appropriate access
  110. to complete the operation.
  111. STATUS_OBJECT_NAME_COLLISION - A Secret object having the given name
  112. already exists.
  113. STATUS_TOO_MANY_SECRETS - The maximum number of Secret objects in the
  114. system has been reached.
  115. STATUS_NAME_TOO_LONG - The name of the secret is too long to be stored
  116. in the LSA database.
  117. --*/
  118. {
  119. NTSTATUS Status, SecondaryStatus;
  120. LSAP_DB_OBJECT_INFORMATION ObjectInformation;
  121. BOOLEAN ContainerReferenced = FALSE;
  122. ULONG CriticalValue = 0;
  123. LSAP_DB_ATTRIBUTE Attributes[3];
  124. ULONG TypeSpecificAttributeCount;
  125. LARGE_INTEGER CreationTime;
  126. ULONG Index;
  127. ULONG CreateOptions = 0;
  128. ULONG CreateDisp = 0;
  129. ULONG ReferenceOptions = LSAP_DB_LOCK |
  130. LSAP_DB_NO_DS_OP_TRANSACTION |
  131. LSAP_DB_READ_ONLY_TRANSACTION;
  132. ULONG DereferenceOptions = LSAP_DB_LOCK |
  133. LSAP_DB_NO_DS_OP_TRANSACTION |
  134. LSAP_DB_READ_ONLY_TRANSACTION;
  135. BOOLEAN GlobalSecret = FALSE;
  136. BOOLEAN DsTrustedDomainSecret = FALSE;
  137. ULONG SecretType;
  138. LSAP_DB_HANDLE InternalHandle;
  139. LsarpReturnCheckSetup();
  140. LsapEnterFunc( "LsarCreateSecret" );
  141. //
  142. // Check to see if the lenght of the name is within the limits of the
  143. // LSA database.
  144. //
  145. if ( SecretName->Length > LSAP_DB_LOGICAL_NAME_MAX_LENGTH ) {
  146. LsapExitFunc( "LsarCreateSecret", STATUS_NAME_TOO_LONG );
  147. return(STATUS_NAME_TOO_LONG);
  148. }
  149. //
  150. // Validate the input buffer
  151. //
  152. if ( !LsapValidateLsaUnicodeString( SecretName ) ) {
  153. Status = STATUS_INVALID_PARAMETER;
  154. goto CreateSecretError;
  155. }
  156. //
  157. // Check for Local Secret creation request. If the Secret name does
  158. // not begin with the Global Secret Prefix, the Secret is local. In
  159. // this case, creation of the secret is allowed on BDC's as well as
  160. // PDC's and Workstations. Creation of Global Secrets is not
  161. // allowed on BDC's except for trusted callers such as a Replicator.
  162. //
  163. SecretType = LsapDbGetSecretType( SecretName );
  164. if ( FLAG_ON( SecretType, LSAP_DB_SECRET_GLOBAL ) ) {
  165. GlobalSecret = TRUE;
  166. }
  167. if (!GlobalSecret) {
  168. CreateOptions |= LSAP_DB_OMIT_REPLICATOR_NOTIFICATION;
  169. ReferenceOptions |= LSAP_DB_OMIT_REPLICATOR_NOTIFICATION;
  170. } else {
  171. CreateOptions |= LSAP_DB_OBJECT_SCOPE_DS;
  172. }
  173. //
  174. // It isn't legal to create a TrustedDomain secret of the form G$$<DomainName>.
  175. //
  176. // There is a race condition between creating such secrets and converting the
  177. // TDO between inbound and outbound. It is pragmatic to simply not allow
  178. // creation of G$$ secrets and then not worry about morphing such objects into TDOs.
  179. //
  180. if ( FLAG_ON( SecretType, LSAP_DB_SECRET_TRUSTED_DOMAIN ) ) {
  181. Status = STATUS_INVALID_PARAMETER;
  182. goto CreateSecretError;
  183. }
  184. //
  185. // Acquire the Lsa Database lock. Verify that the connection handle
  186. // (container object handle) is valid, is of the expected type and has
  187. // all of the desired accesses granted. Reference the container
  188. // object handle.
  189. //
  190. Status = LsapDbReferenceObject(
  191. PolicyHandle,
  192. POLICY_CREATE_SECRET,
  193. PolicyObject,
  194. SecretObject,
  195. ReferenceOptions
  196. );
  197. if (!NT_SUCCESS(Status)) {
  198. goto CreateSecretError;
  199. }
  200. ContainerReferenced = TRUE;
  201. //
  202. // Fill in the ObjectInformation structure. Initialize the
  203. // embedded Object Attributes with the PolicyHandle as the
  204. // Root Directory (Container Object) handle and the Logical Name
  205. // of the account. Store the types of the object and its container.
  206. //
  207. InitializeObjectAttributes(
  208. &ObjectInformation.ObjectAttributes,
  209. (PUNICODE_STRING)SecretName,
  210. OBJ_CASE_INSENSITIVE,
  211. PolicyHandle,
  212. NULL
  213. );
  214. ObjectInformation.ObjectTypeId = SecretObject;
  215. ObjectInformation.ContainerTypeId = PolicyObject;
  216. ObjectInformation.Sid = NULL;
  217. ObjectInformation.ObjectAttributeNameOnly = FALSE;
  218. ObjectInformation.DesiredObjectAccess = DesiredAccess;
  219. //
  220. // Set up the Creation Time as a Type Specific Attribute.
  221. //
  222. GetSystemTimeAsFileTime( (LPFILETIME) &CreationTime );
  223. Index = 0;
  224. LsapDbInitializeAttributeDs( &Attributes[Index],
  225. CupdTime,
  226. &CreationTime,
  227. sizeof( LARGE_INTEGER ),
  228. FALSE );
  229. Index++;
  230. LsapDbInitializeAttributeDs( &Attributes[Index],
  231. OupdTime,
  232. &CreationTime,
  233. sizeof( LARGE_INTEGER ),
  234. FALSE );
  235. Index++;
  236. TypeSpecificAttributeCount = Index;
  237. //
  238. // We'll have to see whether we have a global secret for a trusted domain in the
  239. // DS or just a global secret. If it's the first case, we'll need to locate the
  240. // TrustedDomain object and then we'll set the attributes on that.
  241. //
  242. if ( GlobalSecret ) {
  243. Status = LsapDsIsSecretDsTrustedDomain( (PUNICODE_STRING)SecretName,
  244. &ObjectInformation,
  245. CreateOptions,
  246. DesiredAccess,
  247. SecretHandle,
  248. &DsTrustedDomainSecret );
  249. //
  250. // If it's a Ds trusted domain, we don't do anything with it. If it's a global secret,
  251. // then we'll go ahead and do our normal proceesing
  252. //
  253. if ( NT_SUCCESS( Status ) ) {
  254. if ( DsTrustedDomainSecret ) {
  255. goto CreateSecretFinish;
  256. }
  257. }
  258. if ( LsaDsStateInfo.UseDs ) {
  259. CreateDisp = LSAP_DB_CREATE_OBJECT_IN_DS;
  260. //
  261. // We are doing secret creation. This means that this an object that we'll need to
  262. // mark for initial system replication when setting up a new replica
  263. //
  264. CriticalValue = 1;
  265. LsapDbInitializeAttributeDs( &Attributes[Index],
  266. PseudoSystemCritical,
  267. &CriticalValue,
  268. sizeof( ULONG ),
  269. FALSE );
  270. Index++;
  271. TypeSpecificAttributeCount++;
  272. }
  273. }
  274. ASSERT( sizeof( Attributes ) / sizeof( LSAP_DB_ATTRIBUTE ) >= TypeSpecificAttributeCount );
  275. if ( NT_SUCCESS( Status ) ) {
  276. //
  277. // Create the Secret Object. We fail if the object already exists.
  278. // Note that the object create routine performs a Database transaction.
  279. //
  280. Status = LsapDbCreateObject(
  281. &ObjectInformation,
  282. DesiredAccess,
  283. LSAP_DB_OBJECT_CREATE | CreateDisp,
  284. CreateOptions,
  285. Attributes,
  286. &TypeSpecificAttributeCount,
  287. RTL_NUMBER_OF(Attributes),
  288. SecretHandle
  289. );
  290. //
  291. // If we are creating a secret in the ds, set the flag in the handle to know that
  292. // we just created the secret. We'll use this later on to urgently replicate the change
  293. //
  294. if ( NT_SUCCESS( Status ) && GlobalSecret ) {
  295. ((LSAP_DB_HANDLE)( *SecretHandle ) )->Options |= LSAP_DB_HANDLE_CREATED_SECRET;
  296. }
  297. //
  298. // Set the internal secret flag if necessary
  299. //
  300. if ( NT_SUCCESS( Status ) ) {
  301. InternalHandle = ( LSAP_DB_HANDLE )( *SecretHandle );
  302. if ( FLAG_ON( SecretType, LSAP_DB_SECRET_LOCAL ) ) {
  303. InternalHandle->ObjectOptions |= LSAP_DB_OBJECT_SECRET_LOCAL;
  304. }
  305. if ( FLAG_ON( SecretType, LSAP_DB_SECRET_SYSTEM ) ) {
  306. InternalHandle->ObjectOptions |= LSAP_DB_OBJECT_SECRET_INTERNAL;
  307. }
  308. }
  309. }
  310. if (!NT_SUCCESS(Status)) {
  311. goto CreateSecretError;
  312. }
  313. CreateSecretFinish:
  314. //
  315. // If necessary, release the LSA Database lock.
  316. //
  317. if (ContainerReferenced) {
  318. LsapDbApplyTransaction( PolicyHandle,
  319. LSAP_DB_NO_DS_OP_TRANSACTION |
  320. LSAP_DB_READ_ONLY_TRANSACTION,
  321. (SECURITY_DB_DELTA_TYPE) 0 );
  322. LsapDbReleaseLockEx( SecretObject,
  323. LSAP_DB_READ_ONLY_TRANSACTION);
  324. }
  325. #ifdef TRACK_HANDLE_CLOSE
  326. if (*SecretHandle == LsapDbHandle)
  327. {
  328. DbgPrint("Closing global policy handle!!!\n");
  329. DbgBreakPoint();
  330. }
  331. #endif
  332. LsarpReturnPrologue();
  333. LsapDsDebugOut(( DEB_FTRACE, "LsarCreateSecret: 0x%lx\n", Status ));
  334. return( Status );
  335. CreateSecretError:
  336. //
  337. // If necessary, dereference the Container Object.
  338. //
  339. if (ContainerReferenced) {
  340. SecondaryStatus = LsapDbDereferenceObject(
  341. &PolicyHandle,
  342. PolicyObject,
  343. SecretObject,
  344. DereferenceOptions,
  345. (SECURITY_DB_DELTA_TYPE) 0,
  346. Status
  347. );
  348. LsapDbSetStatusFromSecondary( Status, SecondaryStatus );
  349. ContainerReferenced = FALSE;
  350. }
  351. goto CreateSecretFinish;
  352. }
  353. NTSTATUS
  354. LsarOpenSecret(
  355. IN LSAPR_HANDLE ConnectHandle,
  356. IN PLSAPR_UNICODE_STRING SecretName,
  357. IN ACCESS_MASK DesiredAccess,
  358. OUT PLSAPR_HANDLE SecretHandle
  359. )
  360. /*++
  361. Routine Description:
  362. This function is the LSA server RPC worker routine for the LsaOpenSecret
  363. API.
  364. The LsaOpenSecret API opens a Secret Object within the LSA Database.
  365. A handle is returned which must be used to perform operations on the
  366. secret object.
  367. Arguments:
  368. ConnectHandle - Handle from an LsaOpenLsa call.
  369. DesiredAccess - This is an access mask indicating accesses being
  370. requested for the secret object being opened. These access types
  371. are reconciled with the Discretionary Access Control List of the
  372. target secret object to determine whether the accesses will be
  373. granted or denied.
  374. SecretName - Pointer to a Unicode String structure that references the
  375. name of the Secret object to be opened.
  376. SecretHandle - Pointer to location that will receive a handle to the
  377. newly opened Secret object.
  378. Return Value:
  379. NTSTATUS - Standard Nt Result Code
  380. STATUS_ACCESS_DENIED - Caller does not have the appropriate access
  381. to complete the operation.
  382. STATUS_OBJECT_NAME_NOT_FOUND - There is no Secret object in the
  383. target system's LSA Database having the specified SecretName.
  384. --*/
  385. {
  386. NTSTATUS Status, SecondaryStatus;
  387. LSAP_DB_OBJECT_INFORMATION ObjectInformation;
  388. BOOLEAN ContainerReferenced = FALSE;
  389. BOOLEAN AcquiredLock = FALSE;
  390. BOOLEAN GlobalSecret = FALSE;
  391. ULONG OpenOptions = 0;
  392. ULONG ReferenceOptions = LSAP_DB_LOCK |
  393. LSAP_DB_NO_DS_OP_TRANSACTION |
  394. LSAP_DB_READ_ONLY_TRANSACTION;
  395. BOOLEAN DsTrustedDomainSecret = FALSE;
  396. ULONG SecretType;
  397. LSAP_DB_HANDLE InternalHandle;
  398. LsarpReturnCheckSetup();
  399. LsapDsDebugOut(( DEB_FTRACE, "LsarOpenSecret\n" ));
  400. //
  401. // Validate the input buffer
  402. //
  403. if ( !LsapValidateLsaUnicodeString( SecretName ) ) {
  404. Status = STATUS_INVALID_PARAMETER;
  405. goto OpenSecretError;
  406. }
  407. //
  408. // Check for Local Secret open request. If the Secret name does
  409. // not begin with the Global Secret Prefix, the Secret is local. In
  410. // this case, update/deletion of the secret is allowed on BDC's as well as
  411. // PDC's and Workstations. Update/deletion of Global Secrets is not
  412. // allowed on BDC's except for trusted callers such as a Replicator.
  413. // To facilitate validation of the open request on BDC's we record
  414. // that the BDC check should be omitted on the container reference, and
  415. // that the replicator notification should be omitted on a commit.
  416. //
  417. SecretType = LsapDbGetSecretType( SecretName );
  418. if ( FLAG_ON( SecretType, LSAP_DB_SECRET_GLOBAL ) ) {
  419. GlobalSecret = TRUE;
  420. }
  421. if (!GlobalSecret) {
  422. OpenOptions |= LSAP_DB_OMIT_REPLICATOR_NOTIFICATION;
  423. }
  424. //
  425. // Acquire the Lsa Database lock. Verify that the connection handle
  426. // (container object handle) is valid, and is of the expected type.
  427. // Reference the container object handle. This reference remains in
  428. // effect until the child object handle is closed.
  429. //
  430. Status = LsapDbReferenceObject(
  431. ConnectHandle,
  432. 0,
  433. PolicyObject,
  434. SecretObject,
  435. ReferenceOptions
  436. );
  437. if (!NT_SUCCESS(Status)) {
  438. goto OpenSecretError;
  439. }
  440. AcquiredLock = TRUE;
  441. ContainerReferenced =TRUE;
  442. //
  443. // Setup Object Information prior to calling the LSA Database Object
  444. // Open routine. The Object Type, Container Object Type and
  445. // Logical Name (derived from the Sid) need to be filled in.
  446. //
  447. ObjectInformation.ObjectTypeId = SecretObject;
  448. ObjectInformation.ContainerTypeId = PolicyObject;
  449. ObjectInformation.Sid = NULL;
  450. ObjectInformation.ObjectAttributeNameOnly = FALSE;
  451. ObjectInformation.DesiredObjectAccess = DesiredAccess;
  452. //
  453. // Initialize the Object Attributes. The Container Object Handle and
  454. // Logical Name (Internal Name) of the object must be set up.
  455. //
  456. InitializeObjectAttributes(
  457. &ObjectInformation.ObjectAttributes,
  458. (PUNICODE_STRING)SecretName,
  459. 0,
  460. ConnectHandle,
  461. NULL
  462. );
  463. //
  464. // Open the specific Secret object. Note that the account object
  465. // handle returned is an RPC Context Handle.
  466. //
  467. if ( GlobalSecret ) {
  468. Status = LsapDsIsSecretDsTrustedDomain( (PUNICODE_STRING)SecretName,
  469. &ObjectInformation,
  470. ((LSAP_DB_HANDLE)ConnectHandle)->Options,
  471. DesiredAccess,
  472. SecretHandle,
  473. &DsTrustedDomainSecret );
  474. //
  475. // If it's a Ds trusted domain, we don't do anything with it. If it's a global secret,
  476. // then we'll go ahead and do our normal proceesing
  477. //
  478. if ( NT_SUCCESS( Status ) ) {
  479. if( DsTrustedDomainSecret ) {
  480. InternalHandle = ( LSAP_DB_HANDLE )( *SecretHandle );
  481. InternalHandle->ObjectOptions |= LSAP_DB_OBJECT_SECRET_INTERNAL;
  482. goto OpenSecretFinish;
  483. } else {
  484. OpenOptions |= LSAP_DB_OBJECT_SCOPE_DS;
  485. }
  486. }
  487. }
  488. if ( NT_SUCCESS( Status ) ) {
  489. Status = LsapDbOpenObject( &ObjectInformation,
  490. DesiredAccess,
  491. OpenOptions,
  492. SecretHandle );
  493. if ( Status == STATUS_OBJECT_NAME_NOT_FOUND && GlobalSecret ) {
  494. //
  495. // It's possible that we have a manually created global secret... This
  496. // would not have the SECRET postfix on the name...
  497. //
  498. ObjectInformation.ObjectAttributeNameOnly = TRUE;
  499. Status = LsapDbOpenObject( &ObjectInformation,
  500. DesiredAccess,
  501. OpenOptions,
  502. SecretHandle );
  503. }
  504. //
  505. // Set the internal secret flag if necessary
  506. //
  507. if ( NT_SUCCESS( Status ) ) {
  508. InternalHandle = ( LSAP_DB_HANDLE )( *SecretHandle );
  509. if ( FLAG_ON( SecretType, LSAP_DB_SECRET_LOCAL ) ) {
  510. InternalHandle->ObjectOptions |= LSAP_DB_OBJECT_SECRET_LOCAL;
  511. }
  512. if ( FLAG_ON( SecretType, LSAP_DB_SECRET_SYSTEM ) ) {
  513. InternalHandle->ObjectOptions |= LSAP_DB_OBJECT_SECRET_INTERNAL;
  514. }
  515. }
  516. }
  517. //
  518. // If the open failed, dereference the container object.
  519. //
  520. if (!NT_SUCCESS(Status)) {
  521. goto OpenSecretError;
  522. }
  523. OpenSecretFinish:
  524. //
  525. // If necessary, release the LSA Database lock.
  526. //
  527. if (AcquiredLock) {
  528. LsapDbApplyTransaction( ConnectHandle,
  529. LSAP_DB_NO_DS_OP_TRANSACTION |
  530. LSAP_DB_READ_ONLY_TRANSACTION,
  531. (SECURITY_DB_DELTA_TYPE) 0 );
  532. LsapDbReleaseLockEx( SecretObject,
  533. LSAP_DB_READ_ONLY_TRANSACTION );
  534. }
  535. #ifdef TRACK_HANDLE_CLOSE
  536. if (*SecretHandle == LsapDbHandle)
  537. {
  538. DbgPrint("Closing global policy handle!!!\n");
  539. DbgBreakPoint();
  540. }
  541. #endif
  542. LsarpReturnPrologue();
  543. LsapDsDebugOut(( DEB_FTRACE, "LsarOpenSecret:0x%lx\n", Status ));
  544. return(Status);
  545. OpenSecretError:
  546. //
  547. // If necessary, dereference the Container Object handle. Note that
  548. // this is only done in the error case. In the non-error case, the
  549. // Container handle stays referenced until the Account object is
  550. // closed.
  551. //
  552. if (ContainerReferenced) {
  553. *SecretHandle = NULL;
  554. SecondaryStatus = LsapDbDereferenceObject(
  555. &ConnectHandle,
  556. PolicyObject,
  557. SecretObject,
  558. LSAP_DB_NO_DS_OP_TRANSACTION |
  559. LSAP_DB_READ_ONLY_TRANSACTION,
  560. (SECURITY_DB_DELTA_TYPE) 0,
  561. Status
  562. );
  563. LsapDbSetStatusFromSecondary( Status, SecondaryStatus );
  564. }
  565. goto OpenSecretFinish;
  566. }
  567. NTSTATUS
  568. LsapNotifySecurityPackagesOfPasswordChange(
  569. IN PLSAP_CR_CLEAR_VALUE CurrentValue,
  570. IN OPTIONAL PLSAP_CR_CLEAR_VALUE OldValue
  571. )
  572. /*++
  573. Routine Description:
  574. Call the Kerberos package to let it know that the machine's
  575. password has changed. This should only be called after it has
  576. been updated successfully on the server.
  577. Arguments:
  578. NewPassword - The new NT OWF for the machine.
  579. Return Value:
  580. none
  581. --*/
  582. {
  583. SECPKG_PRIMARY_CRED PrimaryCred;
  584. ULONG_PTR OldPackage;
  585. PLSAP_SECURITY_PACKAGE pAuxPackage;
  586. NTSTATUS scRet = STATUS_SUCCESS;
  587. //
  588. // If we are being called during initialization
  589. // then return success.
  590. //
  591. if (!LsapDbState.DbServerInitialized)
  592. {
  593. return( STATUS_SUCCESS);
  594. }
  595. if ( CurrentValue == NULL ) {
  596. return( STATUS_SUCCESS );
  597. }
  598. DebugLog((DEB_TRACE, "Updating machine credentials.\n"));
  599. RtlZeroMemory(
  600. &PrimaryCred,
  601. sizeof(PrimaryCred)
  602. );
  603. PrimaryCred.Password.Buffer = (LPWSTR) CurrentValue->Buffer;
  604. PrimaryCred.Password.Length = (USHORT) CurrentValue->Length;
  605. PrimaryCred.Password.MaximumLength = (USHORT) CurrentValue->MaximumLength;
  606. PrimaryCred.Flags = PRIMARY_CRED_CLEAR_PASSWORD | PRIMARY_CRED_UPDATE;
  607. if (OldValue != NULL)
  608. {
  609. PrimaryCred.OldPassword.Buffer = (LPWSTR) OldValue->Buffer;
  610. PrimaryCred.OldPassword.Length = (USHORT) OldValue->Length;
  611. PrimaryCred.OldPassword.MaximumLength = (USHORT) OldValue->MaximumLength;
  612. }
  613. OldPackage = GetCurrentPackageId();
  614. pAuxPackage = SpmpIteratePackagesByRequest( NULL, SP_ORDINAL_ACCEPTCREDS );
  615. while (pAuxPackage)
  616. {
  617. ULONG_PTR iPackage;
  618. LUID NetworkServiceLogonId = NETWORKSERVICE_LUID;
  619. iPackage = pAuxPackage->dwPackageID;
  620. DebugLog((DEB_TRACE_INIT, "Updating package %ws with %x:%xn",
  621. pAuxPackage->Name.Buffer,
  622. SystemLogonId.HighPart, SystemLogonId.LowPart
  623. ));
  624. SetCurrentPackageId(iPackage);
  625. //
  626. // call each package twice:
  627. // once for the SYSTEM_LUID
  628. // once for the NETWORKSERVICE_LUID
  629. //
  630. // Note: if an exception occurs, we don't fail the logon, we just
  631. // do the magic on the package that blew. If the package blows,
  632. // the other packages may succeed, and so the user may not be able
  633. // to use that provider.
  634. PrimaryCred.LogonId = SystemLogonId;
  635. __try
  636. {
  637. scRet = pAuxPackage->FunctionTable.AcceptCredentials(
  638. Interactive,
  639. NULL,
  640. &PrimaryCred,
  641. NULL // no supplemental credentials
  642. );
  643. }
  644. __except (EXCEPTION_EXECUTE_HANDLER)
  645. {
  646. scRet = (NTSTATUS) GetExceptionCode();
  647. scRet = SPException(scRet, iPackage);
  648. }
  649. PrimaryCred.LogonId = NetworkServiceLogonId;
  650. __try
  651. {
  652. scRet = pAuxPackage->FunctionTable.AcceptCredentials(
  653. Interactive,
  654. NULL,
  655. &PrimaryCred,
  656. NULL // no supplemental credentials
  657. );
  658. }
  659. __except (EXCEPTION_EXECUTE_HANDLER)
  660. {
  661. scRet = (NTSTATUS) GetExceptionCode();
  662. scRet = SPException(scRet, iPackage);
  663. }
  664. pAuxPackage = SpmpIteratePackagesByRequest( pAuxPackage,
  665. SP_ORDINAL_ACCEPTCREDS );
  666. }
  667. //
  668. // Finally, set this thread back.
  669. //
  670. SetCurrentPackageId( OldPackage );
  671. return scRet;
  672. }
  673. #if defined(REMOTE_BOOT)
  674. NTSTATUS
  675. LsapNotifyRemoteBootOfPasswordChange(
  676. IN PLSAP_CR_CLEAR_VALUE CurrentValue,
  677. IN OPTIONAL PLSAP_CR_CLEAR_VALUE OldValue
  678. )
  679. /*++
  680. Routine Description:
  681. Call the remote boot package to let it know that the machine's
  682. password has changed.
  683. Arguments:
  684. CurrentValue - The cleartext new password.
  685. OldValue - The cleartext old password.
  686. Return Value:
  687. Result of the operation.
  688. --*/
  689. {
  690. NTSTATUS Status ;
  691. HANDLE RdrDevice ;
  692. UNICODE_STRING String ;
  693. OBJECT_ATTRIBUTES ObjA ;
  694. ULONG SetPasswordLength ;
  695. PLMMR_RI_SET_NEW_PASSWORD SetPassword ;
  696. IO_STATUS_BLOCK IoStatus ;
  697. //
  698. // Open the redirector device.
  699. //
  700. RtlInitUnicodeString( &String, DD_NFS_DEVICE_NAME_U );
  701. InitializeObjectAttributes( &ObjA,
  702. &String,
  703. 0,
  704. 0,
  705. 0);
  706. Status = NtOpenFile( &RdrDevice,
  707. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
  708. &ObjA,
  709. &IoStatus,
  710. FILE_SHARE_READ | FILE_SHARE_WRITE,
  711. 0 );
  712. if ( !NT_SUCCESS( Status ) )
  713. {
  714. DebugLog(( DEB_ERROR, "FAILED to open %ws, status %x\n",
  715. String.Buffer, Status ));
  716. return Status;
  717. }
  718. //
  719. // Construct the buffer that has the passwords in it.
  720. //
  721. SetPasswordLength = FIELD_OFFSET(LMMR_RI_SET_NEW_PASSWORD, Data[0]) +
  722. CurrentValue->Length;
  723. if (ARGUMENT_PRESENT(OldValue)) {
  724. SetPasswordLength += OldValue->Length;
  725. }
  726. SetPassword = (PLMMR_RI_SET_NEW_PASSWORD) LsapAllocateLsaHeap( SetPasswordLength );
  727. if (SetPassword == NULL) {
  728. NtClose(RdrDevice);
  729. return STATUS_INSUFFICIENT_RESOURCES;
  730. }
  731. SetPassword->Length1 = CurrentValue->Length;
  732. if (ARGUMENT_PRESENT(OldValue)) {
  733. SetPassword->Length2 = OldValue->Length;
  734. } else {
  735. SetPassword->Length2 = 0;
  736. }
  737. RtlCopyMemory(
  738. SetPassword->Data,
  739. CurrentValue->Buffer,
  740. CurrentValue->Length);
  741. if (ARGUMENT_PRESENT(OldValue)) {
  742. RtlCopyMemory(
  743. SetPassword->Data + CurrentValue->Length,
  744. OldValue->Buffer,
  745. OldValue->Length);
  746. }
  747. Status = NtFsControlFile(
  748. RdrDevice,
  749. NULL,
  750. NULL,
  751. NULL,
  752. &IoStatus,
  753. FSCTL_LMMR_RI_SET_NEW_PASSWORD,
  754. SetPassword,
  755. SetPasswordLength,
  756. NULL,
  757. 0 );
  758. if ( !NT_SUCCESS( Status ) )
  759. {
  760. DebugLog(( DEB_ERROR, "FAILED to FSCTL_LMMR_RI_SET_NEW_PASSWORD %ws, status %x\n",
  761. String.Buffer, Status ));
  762. }
  763. LsapFreeLsaHeap(SetPassword);
  764. NtClose(RdrDevice);
  765. return Status;
  766. }
  767. NTSTATUS
  768. LsapCheckRemoteBootForPasswordChange(
  769. IN LSAP_DB_HANDLE InternalHandle
  770. )
  771. /*++
  772. Routine Description:
  773. Check with the remote boot package to see if the machine account
  774. secret has changed, and if so, set the new value.
  775. NOTE: This routine is called with the database lock held.
  776. Arguments:
  777. InternalHandle - A handle to the machine account secret.
  778. Return Value:
  779. Result of the operation.
  780. --*/
  781. {
  782. NTSTATUS Status;
  783. UNICODE_STRING DeviceName;
  784. IO_STATUS_BLOCK IoStatusBlock;
  785. OBJECT_ATTRIBUTES ObjectAttributes;
  786. HANDLE RedirHandle = NULL;
  787. UCHAR PacketBuffer[sizeof(ULONG)+64];
  788. PLMMR_RI_CHECK_FOR_NEW_PASSWORD RequestPacket = (PLMMR_RI_CHECK_FOR_NEW_PASSWORD)PacketBuffer;
  789. LSAPR_HANDLE SecretHandle = NULL;
  790. PLSAP_CR_CIPHER_VALUE CurrentValue = NULL;
  791. LSAP_CR_CLEAR_VALUE NewValue;
  792. //
  793. // First see if the redirector has a new password to tell us. This
  794. // will fail unless the password has changed while the machine is
  795. // off.
  796. //
  797. RtlInitUnicodeString(&DeviceName, DD_NFS_DEVICE_NAME_U);
  798. InitializeObjectAttributes(
  799. &ObjectAttributes,
  800. &DeviceName,
  801. OBJ_CASE_INSENSITIVE,
  802. NULL,
  803. NULL
  804. );
  805. Status = NtOpenFile(
  806. &RedirHandle,
  807. SYNCHRONIZE,
  808. &ObjectAttributes,
  809. &IoStatusBlock,
  810. 0,
  811. 0
  812. );
  813. if (NT_SUCCESS(Status)) {
  814. Status = IoStatusBlock.Status;
  815. }
  816. if (!NT_SUCCESS(Status)) {
  817. DebugLog(( DEB_ERROR, "FAILED to open %ws, status %x\n",
  818. DeviceName.Buffer, Status ));
  819. Status = STATUS_SUCCESS;
  820. goto CheckRemoteBootFinish;
  821. }
  822. //
  823. // Send the request to the redir.
  824. //
  825. Status = NtFsControlFile(
  826. RedirHandle,
  827. NULL,
  828. NULL,
  829. NULL,
  830. &IoStatusBlock,
  831. FSCTL_LMMR_RI_CHECK_FOR_NEW_PASSWORD,
  832. NULL, // no input buffer
  833. 0,
  834. PacketBuffer,
  835. sizeof(PacketBuffer));
  836. if (NT_SUCCESS(Status)) {
  837. Status = IoStatusBlock.Status;
  838. }
  839. if ( !NT_SUCCESS( Status ) )
  840. {
  841. Status = STATUS_SUCCESS;
  842. goto CheckRemoteBootFinish;
  843. }
  844. //
  845. // The redir thinks there is a new password, so query the current
  846. // one, and set the new one as the current one and the current
  847. // one as the old one.
  848. //
  849. Status = LsarOpenSecret( LsapPolicyHandle,
  850. (PLSAPR_UNICODE_STRING)&LsapMachineSecret,
  851. MAXIMUM_ALLOWED,
  852. &SecretHandle );
  853. if (!NT_SUCCESS(Status)) {
  854. DebugLog(( DEB_ERROR, "FAILED to LsarOpenSecret for remote boot, status %x\n",
  855. Status ));
  856. goto CheckRemoteBootError;
  857. }
  858. //
  859. // Query the Current Value attribute of the Secret Object.
  860. //
  861. Status = LsapDbQueryValueSecret(
  862. SecretHandle,
  863. CurrVal,
  864. NULL,
  865. &CurrentValue
  866. );
  867. if (!NT_SUCCESS(Status)) {
  868. DebugLog(( DEB_ERROR, "FAILED to LsarDbQueryValueSecret for remote boot, status %x\n",
  869. Status ));
  870. goto CheckRemoteBootError;
  871. }
  872. //
  873. // Set the new value if it is different from the current one.
  874. //
  875. NewValue.Length = RequestPacket->Length;
  876. NewValue.MaximumLength = RequestPacket->Length;
  877. NewValue.Buffer = RequestPacket->Data;
  878. if ((CurrentValue->Length != NewValue.Length) ||
  879. !RtlEqualMemory(CurrentValue->Buffer, NewValue.Buffer, CurrentValue->Length)) {
  880. Status = LsapDbSetSecret( SecretHandle,
  881. ( PLSAPR_CR_CIPHER_VALUE )&NewValue,
  882. NULL,
  883. ( PLSAPR_CR_CIPHER_VALUE )CurrentValue,
  884. NULL
  885. #if defined(REMOTE_BOOT)
  886. ,
  887. TRUE
  888. #endif // defined(REMOTE_BOOT)
  889. ); // this is a remote boot machine password change
  890. if (!NT_SUCCESS(Status)) {
  891. DebugLog(( DEB_ERROR, "FAILED to LsapDbSetSecret for remote boot, status %x\n",
  892. Status ));
  893. goto CheckRemoteBootError;
  894. }
  895. }
  896. CheckRemoteBootFinish:
  897. if (RedirHandle != NULL) {
  898. NtClose(RedirHandle);
  899. }
  900. if (SecretHandle != NULL) {
  901. LsapCloseHandle(&SecretHandle, Status);
  902. }
  903. if (CurrentValue != NULL) {
  904. MIDL_user_free(CurrentValue);
  905. }
  906. return(Status);
  907. CheckRemoteBootError:
  908. goto CheckRemoteBootFinish;
  909. }
  910. #endif // defined(REMOTE_BOOT)
  911. NTSTATUS
  912. LsarSetSecret(
  913. IN LSAPR_HANDLE SecretHandle,
  914. IN OPTIONAL PLSAPR_CR_CIPHER_VALUE CipherCurrentValue,
  915. IN OPTIONAL PLSAPR_CR_CIPHER_VALUE CipherOldValue
  916. )
  917. {
  918. return LsapDbSetSecret( SecretHandle,
  919. CipherCurrentValue,
  920. NULL,
  921. CipherOldValue,
  922. NULL
  923. #if defined(REMOTE_BOOT)
  924. ,
  925. FALSE
  926. #endif // defined(REMOTE_BOOT)
  927. ); // not a remote boot machine password change
  928. }
  929. NTSTATUS
  930. LsapDbSetSecret(
  931. IN LSAPR_HANDLE SecretHandle,
  932. IN OPTIONAL PLSAPR_CR_CIPHER_VALUE CipherCurrentValue,
  933. IN OPTIONAL PLARGE_INTEGER CurrentTime,
  934. IN OPTIONAL PLSAPR_CR_CIPHER_VALUE CipherOldValue,
  935. IN OPTIONAL PLARGE_INTEGER OldTime
  936. #if defined(REMOTE_BOOT)
  937. ,
  938. IN BOOLEAN RemoteBootMachinePasswordChange
  939. #endif // defined(REMOTE_BOOT)
  940. )
  941. /*++
  942. Routine Description:
  943. This function is the LSA server RPC worker routine for the LsaSetSecret
  944. API.
  945. The LsaSetSecret API optionally sets one or both values associated with
  946. a Secret object. These values are known as the Current Value and
  947. Old Value of the Secret object and these values have a meaning known to
  948. the creator of the object.
  949. This worker routine receives the Secret values in encrypted form from
  950. the client. A two-way encryption algorithm using the Session Key will
  951. havge been applied. The values received will first be decrypted using
  952. this same key and then two-way encrypted using the LSA Database Private
  953. Encryption Key. The resulting re-encrypted values will then be stored
  954. as attributes of the Secret object.
  955. Arguments:
  956. SecretHandle - Handle from an LsaOpenSecret or LsaCreateSecret call.
  957. CipherCurrentValue - Optional pointer to an encrypted value structure
  958. containing the Current Value (if any) to be set for the Secret
  959. Object (if any). This value is two-way encrypted with the Session
  960. Key. If NULL is specified, the existing Current Value will be left
  961. assigned to the object will be left unchanged.
  962. CipherOldValue - Optional pointer to an encrypted value structure
  963. containing the "old value" (if any) to be set for the Secret
  964. Object (if any). If NULL is specified, the existing Old Value will be
  965. assigned to the object will be left unchanged.
  966. #if defined(REMOTE_BOOT)
  967. RemoteBootMachinePasswordChange - Indicates that a write lock is already
  968. held, that it is OK to let this proceed even if the remote boot state
  969. is CANT_NOTIFY, and that we don't need to notify Kerberos about
  970. the change (because it hasn't initialized yet).
  971. #endif // defined(REMOTE_BOOT)
  972. Return Value:
  973. NTSTATUS - Standard Nt Result Code
  974. STATUS_ACCESS_DENIED - Caller does not have the appropriate access
  975. to complete the operation.
  976. STATUS_INVALID_HANDLE - Handle is invalid.
  977. --*/
  978. {
  979. NTSTATUS Status;
  980. LSAP_DB_HANDLE Handle = (LSAP_DB_HANDLE) SecretHandle;
  981. PLSAP_CR_CLEAR_VALUE ClearCurrentValue = NULL;
  982. PLSAP_CR_CLEAR_VALUE ClearOldValue = NULL;
  983. PLSAP_CR_CIPHER_VALUE DbCipherCurrentValue = NULL;
  984. ULONG DbCipherCurrentValueLength;
  985. PLSAP_CR_CIPHER_VALUE DbCipherOldValue = NULL;
  986. ULONG DbCipherOldValueLength;
  987. PLSAP_CR_CIPHER_KEY SessionKey = NULL;
  988. LARGE_INTEGER UpdatedTime;
  989. LARGE_INTEGER CurrentSecretTime;
  990. BOOLEAN ObjectReferenced = FALSE, FreeOldCipher = FALSE, FreeCurrentCipher = FALSE;
  991. LSAP_DB_HANDLE InternalHandle = (LSAP_DB_HANDLE) SecretHandle;
  992. ULONG ReferenceOptions = LSAP_DB_LOCK | LSAP_DB_START_TRANSACTION | LSAP_DB_NO_DS_OP_TRANSACTION;
  993. ULONG DereferenceOptions = LSAP_DB_LOCK | LSAP_DB_FINISH_TRANSACTION | LSAP_DB_NO_DS_OP_TRANSACTION;
  994. BOOLEAN GlobalSecret= FALSE, DsTrustedDomainSecret = FALSE;
  995. LSAP_DB_ATTRIBUTE Attributes[LSAP_DB_ATTRS_SECRET];
  996. PLSAP_DB_ATTRIBUTE NextAttribute;
  997. ULONG AttributeCount = 0;
  998. BOOLEAN NotifyMachineChange = FALSE;
  999. LsarpReturnCheckSetup();
  1000. LsapDsDebugOut(( DEB_FTRACE, "LsarSetSecret\n" ));
  1001. #if defined(REMOTE_BOOT)
  1002. //
  1003. // If this is a remote boot machine and this request is to set the
  1004. // machine account password, check if we can do it right now. The
  1005. // exception is if the remote boot code is notifying LSA of a changed
  1006. // password, then allow this call through, since it isn't necessary
  1007. // to notify remote boot if it is the source of the change.
  1008. //
  1009. if ((LsapDbState.RemoteBootState == LSAP_DB_REMOTE_BOOT_CANT_NOTIFY) &&
  1010. (RtlEqualUnicodeString(
  1011. &LsapMachineSecret,
  1012. &InternalHandle->LogicalNameU,
  1013. TRUE)) && // case insensitive
  1014. !RemoteBootMachinePasswordChange) {
  1015. DebugLog(( DEB_ERROR, "FAILED LsarSetSecret for machine secret, remote boot can't be notified on this boot.\n" ));
  1016. Status = STATUS_ACCESS_DENIED;
  1017. goto SetSecretError;
  1018. }
  1019. #endif // defined(REMOTE_BOOT)
  1020. //
  1021. // Check for Local Secret set request. If the Secret name does
  1022. // not begin with the Global Secret Prefix, the Secret is local. In
  1023. // this case, update of the secret is allowed on BDC's as well as
  1024. // PDC's and Workstations. Creation of Global Secrets is not
  1025. // allowed on BDC's except for trusted callers such as a Replicator.
  1026. //
  1027. if ( FLAG_ON( InternalHandle->Options, LSAP_DB_DS_TRUSTED_DOMAIN_AS_SECRET ) ) {
  1028. GlobalSecret = TRUE;
  1029. } else {
  1030. ULONG SecretType;
  1031. SecretType = LsapDbGetSecretType( ( PLSAPR_UNICODE_STRING )&InternalHandle->LogicalNameU );
  1032. if ( FLAG_ON( SecretType, LSAP_DB_SECRET_GLOBAL ) ) {
  1033. GlobalSecret = TRUE;
  1034. }
  1035. }
  1036. if ( !GlobalSecret ) {
  1037. DereferenceOptions |= LSAP_DB_OMIT_REPLICATOR_NOTIFICATION;
  1038. }
  1039. //
  1040. // Acquire the Lsa Database lock. Verify that the Secret Object handle is
  1041. // valid, is of the expected type and has all of the desired accesses
  1042. // granted. Reference the handle and open a database transaction.
  1043. //
  1044. #if defined(REMOTE_BOOT)
  1045. // If this is a remote boot machine password change, the lock is
  1046. // already acquired.
  1047. //
  1048. if (!RemoteBootMachinePasswordChange)
  1049. #endif // defined(REMOTE_BOOT)
  1050. {
  1051. Status = LsapDbReferenceObject(
  1052. SecretHandle,
  1053. SECRET_SET_VALUE,
  1054. SecretObject,
  1055. SecretObject,
  1056. ReferenceOptions
  1057. );
  1058. if (!NT_SUCCESS(Status)) {
  1059. goto SetSecretError;
  1060. }
  1061. ObjectReferenced = TRUE;
  1062. }
  1063. if( GlobalSecret ) {
  1064. Status = LsapDsIsHandleDsObjectTypeHandle( SecretHandle,
  1065. TrustedDomainObject,
  1066. &DsTrustedDomainSecret );
  1067. }
  1068. //
  1069. // If the client is non-trusted, obtain the Session Key used by the
  1070. // client to two-way encrypt the Current Value and/or Old Values.
  1071. //
  1072. if (!InternalHandle->Trusted) {
  1073. Status = LsapCrServerGetSessionKey( SecretHandle, &SessionKey);
  1074. if (!NT_SUCCESS(Status)) {
  1075. goto SetSecretError;
  1076. }
  1077. }
  1078. //
  1079. // If a Current Value is specified for the Secret Object, and the
  1080. // client is non-trusted, decrypt the value using the Session Key and
  1081. // encrypt it using the LSA Database System Key. Then (for all
  1082. // clients) encrypt the resulting value with the internal LSA Database
  1083. // encryption key and write resulting Value structure (header followed by
  1084. // buffer to the Policy Database as the Current Value attribute of the
  1085. // Secret object. If no Current Value is specified, or a NULL
  1086. // string is specified, the existing Current Value will be deleted.
  1087. //
  1088. if (ARGUMENT_PRESENT(CipherCurrentValue)) {
  1089. if (!InternalHandle->Trusted) {
  1090. Status = LsapCrDecryptValue(
  1091. (PLSAP_CR_CIPHER_VALUE) CipherCurrentValue,
  1092. SessionKey,
  1093. &ClearCurrentValue
  1094. );
  1095. if (!NT_SUCCESS(Status)) {
  1096. goto SetSecretError;
  1097. }
  1098. } else {
  1099. ClearCurrentValue = (PLSAP_CR_CLEAR_VALUE) CipherCurrentValue;
  1100. }
  1101. }
  1102. //
  1103. // If an Old Value is specified for the Secret Object, and the
  1104. // client is non-trusted, decrypt the value using the Session Key and
  1105. // encrypt it using the LSA Database System Key. Then (for all
  1106. // clients) encrypt the resulting value with the internal LSA Database
  1107. // encryption key and write resulting Value structure (header followed by
  1108. // buffer to the Policy Database as the Old Value attribute of the
  1109. // Secret object. If no Old Value is specified, or a NULL
  1110. // string is specified, the existing Old Value will be deleted.
  1111. //
  1112. if (ARGUMENT_PRESENT(CipherOldValue)) {
  1113. if (!InternalHandle->Trusted) {
  1114. Status = LsapCrDecryptValue(
  1115. (PLSAP_CR_CIPHER_VALUE) CipherOldValue,
  1116. SessionKey,
  1117. &ClearOldValue
  1118. );
  1119. if (!NT_SUCCESS(Status)) {
  1120. goto SetSecretError;
  1121. }
  1122. } else {
  1123. ClearOldValue = (PLSAP_CR_CLEAR_VALUE) CipherOldValue;
  1124. }
  1125. }
  1126. //
  1127. // Get the time at which the Current Secret value was last updated.
  1128. //
  1129. GetSystemTimeAsFileTime( (LPFILETIME) &UpdatedTime );
  1130. //
  1131. // If it's a trusted domain secret, write it out now...
  1132. //
  1133. if ( DsTrustedDomainSecret ) {
  1134. Status = LsapDsSetSecretOnTrustedDomainObject( SecretHandle,
  1135. TRUST_AUTH_TYPE_CLEAR,
  1136. ClearCurrentValue,
  1137. ClearOldValue,
  1138. &UpdatedTime );
  1139. if (!NT_SUCCESS(Status)) {
  1140. goto SetSecretError;
  1141. } else {
  1142. goto SetSecretFinish;
  1143. }
  1144. }
  1145. //
  1146. // If the caller didn't specify an old value,
  1147. // get the current value off the object and use that.
  1148. //
  1149. if ( ClearOldValue == NULL ) {
  1150. BOOLEAN SavedTrusted;
  1151. //
  1152. // Grab the current value of the secret.
  1153. //
  1154. // We may not have access, so go as trusted.
  1155. // Password comes back in the clear.
  1156. //
  1157. SavedTrusted = Handle->Trusted;
  1158. Handle->Trusted = TRUE;
  1159. Status = LsarQuerySecret( SecretHandle,
  1160. &(PLSAPR_CR_CIPHER_VALUE)ClearOldValue,
  1161. &CurrentSecretTime,
  1162. NULL,
  1163. NULL );
  1164. Handle->Trusted = SavedTrusted;
  1165. if ( !NT_SUCCESS(Status)) {
  1166. goto SetSecretError;
  1167. }
  1168. OldTime = &CurrentSecretTime;
  1169. }
  1170. //
  1171. // Now, encrypt them both, if we are not writing to a DS secret
  1172. //
  1173. if ( ClearCurrentValue != NULL ) {
  1174. if ( !LsapDsIsWriteDs( SecretHandle ) ) {
  1175. Status = LsapCrEncryptValue( ClearCurrentValue,
  1176. LsapDbSecretCipherKeyWrite,
  1177. &DbCipherCurrentValue );
  1178. if (!NT_SUCCESS(Status)) {
  1179. goto SetSecretError;
  1180. }
  1181. FreeCurrentCipher = TRUE;
  1182. DbCipherCurrentValueLength = DbCipherCurrentValue->Length
  1183. + sizeof( LSAP_CR_CIPHER_VALUE );
  1184. DbCipherCurrentValue->MaximumLength |= LSAP_DB_SECRET_WIN2K_SYSKEY_ENCRYPTED;
  1185. } else {
  1186. DbCipherCurrentValue = ( PLSAP_CR_CIPHER_VALUE )ClearCurrentValue->Buffer;
  1187. DbCipherCurrentValueLength = ClearCurrentValue->Length;
  1188. }
  1189. } else {
  1190. DbCipherCurrentValue = NULL;
  1191. DbCipherCurrentValueLength = 0;
  1192. }
  1193. if ( ClearOldValue != NULL ) {
  1194. if ( !LsapDsIsWriteDs( SecretHandle ) ) {
  1195. Status = LsapCrEncryptValue( ClearOldValue,
  1196. LsapDbSecretCipherKeyWrite,
  1197. &DbCipherOldValue );
  1198. if (!NT_SUCCESS(Status)) {
  1199. goto SetSecretError;
  1200. }
  1201. FreeOldCipher = TRUE;
  1202. DbCipherOldValueLength = DbCipherOldValue->Length + sizeof( LSAP_CR_CIPHER_VALUE );
  1203. DbCipherOldValue->MaximumLength |= LSAP_DB_SECRET_WIN2K_SYSKEY_ENCRYPTED;
  1204. } else {
  1205. DbCipherOldValue = ( PLSAP_CR_CIPHER_VALUE )ClearOldValue->Buffer;
  1206. DbCipherOldValueLength = ClearOldValue->Length;
  1207. }
  1208. } else {
  1209. DbCipherOldValue = NULL;
  1210. DbCipherOldValueLength = 0;
  1211. }
  1212. //
  1213. // Build the list of attributes
  1214. //
  1215. NextAttribute = Attributes;
  1216. //
  1217. // Current value
  1218. //
  1219. LsapDbInitializeAttributeDs( NextAttribute,
  1220. CurrVal,
  1221. DbCipherCurrentValue,
  1222. DbCipherCurrentValueLength,
  1223. FALSE );
  1224. NextAttribute++;
  1225. AttributeCount++;
  1226. //
  1227. // Current time
  1228. //
  1229. LsapDbInitializeAttributeDs( NextAttribute,
  1230. CupdTime,
  1231. CurrentTime ? CurrentTime : &UpdatedTime,
  1232. sizeof( LARGE_INTEGER ),
  1233. FALSE );
  1234. NextAttribute++;
  1235. AttributeCount++;
  1236. if ( !( LsapDsIsWriteDs( SecretHandle ) && ClearOldValue == NULL ) ) {
  1237. //
  1238. // Previous value
  1239. //
  1240. LsapDbInitializeAttributeDs( NextAttribute,
  1241. OldVal,
  1242. DbCipherOldValue,
  1243. DbCipherOldValueLength,
  1244. FALSE );
  1245. LsapDbAttributeCanNotExist(NextAttribute);
  1246. NextAttribute++;
  1247. AttributeCount++;
  1248. //
  1249. // Previous time
  1250. //
  1251. LsapDbInitializeAttributeDs( NextAttribute,
  1252. OupdTime,
  1253. OldTime ? OldTime : &UpdatedTime,
  1254. sizeof( LARGE_INTEGER ),
  1255. FALSE );
  1256. LsapDbAttributeCanNotExist(NextAttribute);
  1257. NextAttribute++;
  1258. AttributeCount++;
  1259. }
  1260. Status = LsapDbWriteAttributesObject( SecretHandle,
  1261. Attributes,
  1262. AttributeCount );
  1263. if (!NT_SUCCESS(Status)) {
  1264. goto SetSecretError;
  1265. }
  1266. //
  1267. // If this is the machine account, do notification
  1268. //
  1269. if( LsapDbSecretIsMachineAcc( Handle ) ) {
  1270. LsaINotifyChangeNotification( PolicyNotifyMachineAccountPasswordInformation );
  1271. }
  1272. NotifyMachineChange = TRUE;
  1273. SetSecretFinish:
  1274. //
  1275. // If necessary, dereference the Secret object, close the database
  1276. // transaction, notify the LSA Database Replicator of the change,
  1277. // release the LSA Database lock and return. If this is a
  1278. // RemoteBootMachinePasswordChange, ObjectReferenced will be FALSE.
  1279. //
  1280. if (ObjectReferenced) {
  1281. Status = LsapDbDereferenceObject(
  1282. &SecretHandle,
  1283. SecretObject,
  1284. SecretObject,
  1285. DereferenceOptions,
  1286. SecurityDbChange,
  1287. Status
  1288. );
  1289. }
  1290. //
  1291. // If we are changing our machine account password, notify
  1292. // security packages and the remote boot code.
  1293. //
  1294. if (NotifyMachineChange && RtlEqualUnicodeString(
  1295. &LsapMachineSecret,
  1296. &InternalHandle->LogicalNameU,
  1297. TRUE)) { // case insensitive
  1298. #if defined(REMOTE_BOOT)
  1299. //
  1300. // If this is being called due to a remote boot machine password
  1301. // change, we don't need to notify Kerberos, because this will
  1302. // be inside the initial LsarQuerySecret() call that LSA makes,
  1303. // and it notifies Kerberos after that call returns.
  1304. //
  1305. if (!RemoteBootMachinePasswordChange)
  1306. #endif // defined(REMOTE_BOOT)
  1307. {
  1308. (VOID) LsapNotifySecurityPackagesOfPasswordChange(
  1309. ClearCurrentValue,
  1310. ClearOldValue
  1311. );
  1312. }
  1313. #if defined(REMOTE_BOOT)
  1314. //
  1315. // Notify remote boot if it wants to be notified.
  1316. //
  1317. if (LsapDbState.RemoteBootState == LSAP_DB_REMOTE_BOOT_NOTIFY) {
  1318. (VOID) LsapNotifyRemoteBootOfPasswordChange(
  1319. ClearCurrentValue,
  1320. ClearOldValue
  1321. );
  1322. }
  1323. #endif // defined(REMOTE_BOOT)
  1324. }
  1325. //
  1326. // If necessary, free memory allocated for the Session Key.
  1327. //
  1328. if (SessionKey != NULL) {
  1329. MIDL_user_free(SessionKey);
  1330. SessionKey = NULL;
  1331. }
  1332. //
  1333. // If necessary, free memory allocated for the Current Value
  1334. // encrypted for storage in the LSA Database.
  1335. //
  1336. if ( FreeCurrentCipher ) {
  1337. LsapCrFreeMemoryValue( DbCipherCurrentValue );
  1338. DbCipherCurrentValue = NULL;
  1339. }
  1340. //
  1341. // If necessary, free memory allocated for the Old Value
  1342. // encrypted for storage in the LSA Database.
  1343. //
  1344. if ( FreeOldCipher ) {
  1345. LsapCrFreeMemoryValue( DbCipherOldValue );
  1346. DbCipherOldValue = NULL;
  1347. }
  1348. //
  1349. // If necessary, free memory allocated for Decrypted Current Value.
  1350. // Note that for trusted clients, the decryption is the identity
  1351. // mapping, so do not do the free in this case.
  1352. //
  1353. if ((ClearCurrentValue != NULL) && !InternalHandle->Trusted) {
  1354. LsapCrFreeMemoryValue( ClearCurrentValue );
  1355. ClearCurrentValue = NULL;
  1356. }
  1357. //
  1358. // If necessary, free memory allocated for Decrypted Old Value.
  1359. // Note that for trusted clients, the decryption is the identity
  1360. // mapping, so do not do the free in this case.
  1361. //
  1362. if ((ClearOldValue != NULL) && !InternalHandle->Trusted) {
  1363. LsapCrFreeMemoryValue( ClearOldValue );
  1364. ClearOldValue = NULL;
  1365. }
  1366. LsarpReturnPrologue();
  1367. LsapDsDebugOut(( DEB_FTRACE, "LsarSetSecret: 0x%lx\n", Status ));
  1368. return(Status);
  1369. SetSecretError:
  1370. goto SetSecretFinish;
  1371. }
  1372. NTSTATUS
  1373. LsarQuerySecret(
  1374. IN LSAPR_HANDLE SecretHandle,
  1375. IN OUT OPTIONAL PLSAPR_CR_CIPHER_VALUE *CipherCurrentValue,
  1376. OUT OPTIONAL PLARGE_INTEGER CurrentValueSetTime,
  1377. IN OUT OPTIONAL PLSAPR_CR_CIPHER_VALUE *CipherOldValue,
  1378. OUT OPTIONAL PLARGE_INTEGER OldValueSetTime
  1379. )
  1380. /*++
  1381. Routine Description:
  1382. This function is the LSA server RPC worker routine for the LsaQuerySecret
  1383. API.
  1384. The LsaQuerySecret API optionally returns one or both of the values
  1385. assigned to a Secret object. These values are known as the "current value"
  1386. and the "old value", and they have a meaning known to the creator of the
  1387. Secret object. The values are returned in their encrypted form.
  1388. The caller must have LSA_QUERY_SECRET access to the Secret object.
  1389. Arguments:
  1390. SecretHandle - Handle from an LsaOpenSecret or LsaCreateSecret call.
  1391. CipherCurrentValue - Optional pointer to location which will receive a
  1392. pointer to an encrypted Unicode String structure containing the
  1393. "current value" of the Secret Object (if any) in encrypted form.
  1394. If no "current value" is assigned to the Secret object, a NULL pointer
  1395. is returned.
  1396. CurrentValueSetTime - The date/time at which the current secret value
  1397. was established.
  1398. CipherOldValue - Optional pointer to location which will receive a
  1399. pointer to an encrypted Unicode String structure containing the
  1400. "old value" of the Secret Object (if any) in encrypted form.
  1401. If no "old value" is assigned to the Secret object, a NULL pointer
  1402. is returned.
  1403. OldValueSetTime - The date/time at which the old secret value
  1404. was established.
  1405. Return Value:
  1406. NTSTATUS - Standard Nt Result Code
  1407. STATUS_ACCESS_DENIED - Caller does not have the appropriate access
  1408. to complete the operation.
  1409. --*/
  1410. {
  1411. NTSTATUS Status;
  1412. LSAP_DB_HANDLE InternalHandle = (LSAP_DB_HANDLE) SecretHandle;
  1413. PLSAP_CR_CIPHER_VALUE OutputCipherCurrentValue = NULL;
  1414. PLSAP_CR_CIPHER_VALUE OutputCipherOldValue = NULL;
  1415. PLSAP_CR_CIPHER_KEY SessionKey = NULL;
  1416. BOOLEAN ObjectReferenced = FALSE, DsTrustedDomainSecret = FALSE;
  1417. ULONG ValueSetTimeLength;
  1418. LsarpReturnCheckSetup();
  1419. LsapDsDebugOut(( DEB_FTRACE, "LsarQuerySecret\n" ));
  1420. LsapTraceEvent(EVENT_TRACE_TYPE_START, LsaTraceEvent_QuerySecret);
  1421. //
  1422. // If the caller is from a network call and we are opening a local/system secret,
  1423. // return an error
  1424. //
  1425. if ( InternalHandle->NetworkClient && (!InternalHandle->Trusted) &&
  1426. FLAG_ON( InternalHandle->ObjectOptions, LSAP_DB_OBJECT_SECRET_LOCAL ) ) {
  1427. Status = STATUS_ACCESS_DENIED;
  1428. goto QuerySecretReturn;
  1429. }
  1430. //
  1431. // If the caller is not trusted and they are trying to read an internal secret, return
  1432. // an error
  1433. //
  1434. if ( !InternalHandle->Trusted &&
  1435. FLAG_ON( InternalHandle->ObjectOptions, LSAP_DB_OBJECT_SECRET_INTERNAL ) ) {
  1436. Status = STATUS_ACCESS_DENIED;
  1437. goto QuerySecretReturn;
  1438. }
  1439. #if defined(REMOTE_BOOT)
  1440. //
  1441. // If this is a remote boot machine that might notify us of
  1442. // password changes that happened while the machine is off, and
  1443. // this seems to be the first time this routine has been called,
  1444. // then take a write lock in case we need to write the secret
  1445. // (after we take the lock we check to make sure this really is
  1446. // the first time through).
  1447. //
  1448. // It is OK to do the initial check of FirstMachineAccountQueryDone
  1449. // without the lock because it starts as FALSE and changes to TRUE
  1450. // exactly once.
  1451. //
  1452. if ((LsapDbState.RemoteBootState != LSAP_DB_REMOTE_BOOT_NO_NOTIFICATION) &&
  1453. !FirstMachineAccountQueryDone &&
  1454. RtlEqualUnicodeString(
  1455. &LsapMachineSecret,
  1456. &InternalHandle->LogicalNameU,
  1457. TRUE)) { // case insensitive
  1458. NTSTATUS CheckStatus = STATUS_SUCCESS;
  1459. HANDLE TempHandle = SecretHandle;
  1460. //
  1461. // Take the lock with the options that LsarSetSecret will choose
  1462. // to write the machine account secret.
  1463. //
  1464. Status = LsapDbReferenceObject(
  1465. TempHandle,
  1466. SECRET_SET_VALUE,
  1467. SecretObject,
  1468. SecretObject,
  1469. LSAP_DB_LOCK |
  1470. LSAP_DB_START_TRANSACTION |
  1471. LSAP_DB_NO_DS_OP_TRANSACTION
  1472. );
  1473. if (!NT_SUCCESS(Status)) {
  1474. goto QuerySecretError;
  1475. }
  1476. //
  1477. // Now that we have acquired the lock, check again to see if we
  1478. // need to check for a remote boot secret. If FirstMachineAccountQueryDone
  1479. // is now also TRUE, it means another thread did the query at the same
  1480. // time, and since we now have the lock, that thread has finished the
  1481. // query and any resulting updating.
  1482. //
  1483. if (!FirstMachineAccountQueryDone) {
  1484. CheckStatus = LsapCheckRemoteBootForPasswordChange(TempHandle);
  1485. FirstMachineAccountQueryDone = TRUE;
  1486. }
  1487. //
  1488. // We verify CheckStatus after we have dereferenced, so that we
  1489. // always do the dereference.
  1490. //
  1491. Status = LsapDbDereferenceObject(
  1492. &TempHandle,
  1493. SecretObject,
  1494. SecretObject,
  1495. LSAP_DB_LOCK |
  1496. LSAP_DB_FINISH_TRANSACTION |
  1497. LSAP_DB_OMIT_REPLICATOR_NOTIFICATION |
  1498. LSAP_DB_NO_DS_OP_TRANSACTION,
  1499. (SECURITY_DB_DELTA_TYPE) 0,
  1500. Status
  1501. );
  1502. if (!NT_SUCCESS(CheckStatus)) {
  1503. Status = CheckStatus;
  1504. goto QuerySecretError;
  1505. }
  1506. if (!NT_SUCCESS(Status)) {
  1507. goto QuerySecretError;
  1508. }
  1509. }
  1510. #endif // defined(REMOTE_BOOT)
  1511. //
  1512. // If the caller is non-trusted, obtain the Session Key used by the
  1513. // client to two-way encrypt the Current Value and/or Old Values.
  1514. // Trusted Clients do not use encryption since they are calling
  1515. // this server service directly and not via RPC.
  1516. //
  1517. if (!InternalHandle->Trusted) {
  1518. Status = LsapCrServerGetSessionKey( SecretHandle, &SessionKey );
  1519. if (!NT_SUCCESS(Status)) {
  1520. goto QuerySecretError;
  1521. }
  1522. }
  1523. //
  1524. // Acquire the Lsa Database lock. Verify that the Secret Object handle is
  1525. // valid, is of the expected type and has all of the desired accesses
  1526. // granted. Reference the handle and open a database transaction.
  1527. //
  1528. Status = LsapDbReferenceObject(
  1529. SecretHandle,
  1530. SECRET_QUERY_VALUE,
  1531. SecretObject,
  1532. SecretObject,
  1533. LSAP_DB_LOCK |
  1534. LSAP_DB_READ_ONLY_TRANSACTION |
  1535. LSAP_DB_NO_DS_OP_TRANSACTION
  1536. );
  1537. if (!NT_SUCCESS(Status)) {
  1538. goto QuerySecretError;
  1539. }
  1540. ObjectReferenced = TRUE;
  1541. //
  1542. // See if its a trusted domain secret
  1543. //
  1544. Status = LsapDsIsHandleDsObjectTypeHandle( SecretHandle,
  1545. TrustedDomainObject,
  1546. &DsTrustedDomainSecret );
  1547. if ( !NT_SUCCESS( Status ) ) {
  1548. goto QuerySecretError;
  1549. }
  1550. //
  1551. // If it's a Ds trusted domain, go ahead and read the data. Otherwise, pass it along
  1552. //
  1553. if ( DsTrustedDomainSecret ) {
  1554. Status = LsapDsGetSecretOnTrustedDomainObject( SecretHandle,
  1555. SessionKey,
  1556. ARGUMENT_PRESENT(CipherCurrentValue) ?
  1557. &OutputCipherCurrentValue : NULL,
  1558. ARGUMENT_PRESENT(CipherOldValue) ?
  1559. &OutputCipherOldValue : NULL,
  1560. CurrentValueSetTime,
  1561. OldValueSetTime );
  1562. if ( NT_SUCCESS( Status ) ) {
  1563. goto QuerySecretFinish;
  1564. } else {
  1565. goto QuerySecretError;
  1566. }
  1567. }
  1568. //
  1569. // If requested, query the Current Value attribute of the Secret Object.
  1570. // For non-trusted callers, the Current value will be returned in
  1571. // encrypted form embedded within a structure.
  1572. //
  1573. if (ARGUMENT_PRESENT(CipherCurrentValue)) {
  1574. Status = LsapDbQueryValueSecret(
  1575. SecretHandle,
  1576. CurrVal,
  1577. SessionKey,
  1578. &OutputCipherCurrentValue
  1579. );
  1580. if (!NT_SUCCESS(Status)) {
  1581. goto QuerySecretError;
  1582. }
  1583. }
  1584. //
  1585. // If requested, query the Old Value attribute of the Secret Object.
  1586. // For non-trusted callers, the Old Value will be returned in
  1587. // encrypted form embedded within a structure.
  1588. //
  1589. if (ARGUMENT_PRESENT(CipherOldValue)) {
  1590. Status = LsapDbQueryValueSecret(
  1591. SecretHandle,
  1592. OldVal,
  1593. SessionKey,
  1594. &OutputCipherOldValue
  1595. );
  1596. if (!NT_SUCCESS(Status)) {
  1597. goto QuerySecretError;
  1598. }
  1599. }
  1600. ValueSetTimeLength = sizeof (LARGE_INTEGER);
  1601. //
  1602. // If requested, Query the time at which the Current Value of the Secret
  1603. // was last established. If the Current Value has never been set, return
  1604. // the time at which the Secret was created.
  1605. //
  1606. if (ARGUMENT_PRESENT(CurrentValueSetTime)) {
  1607. Status = LsapDbReadAttributeObjectEx(
  1608. SecretHandle,
  1609. CupdTime,
  1610. CurrentValueSetTime,
  1611. &ValueSetTimeLength,
  1612. TRUE
  1613. );
  1614. if (!NT_SUCCESS(Status)) {
  1615. goto QuerySecretError;
  1616. }
  1617. }
  1618. //
  1619. // If requested, Query the time at which the Old Value of the Secret
  1620. // was last established. If the Old Value has never been set, return
  1621. // the time at which the Secret was created.
  1622. //
  1623. if (ARGUMENT_PRESENT(OldValueSetTime)) {
  1624. Status = LsapDbReadAttributeObjectEx(
  1625. SecretHandle,
  1626. OupdTime,
  1627. OldValueSetTime,
  1628. &ValueSetTimeLength,
  1629. TRUE
  1630. );
  1631. if (!NT_SUCCESS(Status)) {
  1632. goto QuerySecretError;
  1633. }
  1634. }
  1635. QuerySecretFinish:
  1636. //
  1637. // If necessary, free memory allocated for the Session Key.
  1638. //
  1639. if (SessionKey != NULL) {
  1640. MIDL_user_free(SessionKey);
  1641. }
  1642. //
  1643. // Return Current and/or Old Values of Secret Object, or NULL to
  1644. // caller. In error cases, NULL will be returned.
  1645. //
  1646. if (ARGUMENT_PRESENT(CipherCurrentValue)) {
  1647. (PLSAP_CR_CIPHER_VALUE) *CipherCurrentValue = OutputCipherCurrentValue;
  1648. }
  1649. if (ARGUMENT_PRESENT(CipherOldValue)) {
  1650. (PLSAP_CR_CIPHER_VALUE) *CipherOldValue = OutputCipherOldValue;
  1651. }
  1652. //
  1653. // If necessary, dereference the Secret object, close the database
  1654. // transaction, release the LSA Database lock and return.
  1655. //
  1656. if (ObjectReferenced) {
  1657. Status = LsapDbDereferenceObject(
  1658. &SecretHandle,
  1659. SecretObject,
  1660. SecretObject,
  1661. LSAP_DB_LOCK |
  1662. LSAP_DB_READ_ONLY_TRANSACTION |
  1663. LSAP_DB_NO_DS_OP_TRANSACTION,
  1664. (SECURITY_DB_DELTA_TYPE) 0,
  1665. Status
  1666. );
  1667. }
  1668. QuerySecretReturn:
  1669. (void) LsapAdtGenerateObjectOperationAuditEvent(
  1670. SecretHandle,
  1671. NT_SUCCESS(Status) ?
  1672. EVENTLOG_AUDIT_SUCCESS : EVENTLOG_AUDIT_FAILURE,
  1673. ObjectOperationQuery
  1674. );
  1675. LsapTraceEvent(EVENT_TRACE_TYPE_END, LsaTraceEvent_QuerySecret);
  1676. LsapDsDebugOut(( DEB_FTRACE, "LsarQuerySecret: 0x%lx\n", Status ));
  1677. LsarpReturnPrologue();
  1678. return(Status);
  1679. QuerySecretError:
  1680. //
  1681. // Deallocate any allocated memory
  1682. //
  1683. if ( OutputCipherCurrentValue ) {
  1684. MIDL_user_free( OutputCipherCurrentValue );
  1685. OutputCipherCurrentValue = NULL;
  1686. }
  1687. if ( OutputCipherOldValue ) {
  1688. MIDL_user_free( OutputCipherOldValue );
  1689. OutputCipherOldValue = NULL;
  1690. }
  1691. goto QuerySecretFinish;
  1692. }
  1693. NTSTATUS
  1694. LsapDbQueryValueSecret(
  1695. IN LSAPR_HANDLE SecretHandle,
  1696. IN LSAP_DB_NAMES ValueIndex,
  1697. IN OPTIONAL PLSAP_CR_CIPHER_KEY SessionKey,
  1698. OUT PLSAP_CR_CIPHER_VALUE *CipherValue
  1699. )
  1700. /*++
  1701. Routine Description:
  1702. This function queries the specified value of a Secret Object. If
  1703. the caller is non-trusted, the value returned will have been two-way
  1704. encrypted with the Session Key. If the caller is trusted, no
  1705. encryption is done since the caller is calling us directly.
  1706. Arguments:
  1707. SecretHandle - Handle to Secret Object.
  1708. ValueName - Unicode name of the Secret Value to be queried. This
  1709. name is either "Currval" (for the Current Value) or "OldVal"
  1710. (for the Old Value.
  1711. SessionKey - Pointer to Session Key to be used for two-way encryption
  1712. of the value to be returned. This pointer must be non-NULL
  1713. except for Trusted Clients, where it must be NULL.
  1714. CipherValue - Receives 32-bit counted string pointer to Secret Value
  1715. queried. For non-trusted clients, the value will be encrypted.
  1716. WARNING - Note that CipherValue is defined to RPC as
  1717. "allocate(all_nodes)". This means that it is returned
  1718. in one contiguous block of memory rather than two, as
  1719. it would appear by the structure definition.
  1720. Return Values:
  1721. NTSTATUS - Standard Nt Result Code.
  1722. STATUS_SUCCESS - The call completed successfully.
  1723. STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources,
  1724. such as memory, to complete the call.
  1725. --*/
  1726. {
  1727. NTSTATUS Status;
  1728. ULONG DbCipherValueLength;
  1729. PLSAP_CR_CLEAR_VALUE ClearValue = NULL;
  1730. PLSAP_CR_CIPHER_VALUE DbCipherValue = NULL;
  1731. PLSAP_CR_CIPHER_VALUE OutputCipherValue = NULL;
  1732. LSAP_DB_HANDLE InternalHandle = (LSAP_DB_HANDLE) SecretHandle;
  1733. //
  1734. // Get length of the specified Value attribute of the Secret object.
  1735. //
  1736. DbCipherValueLength = 0;
  1737. Status = LsapDbReadAttributeObjectEx(
  1738. SecretHandle,
  1739. ValueIndex,
  1740. NULL,
  1741. &DbCipherValueLength,
  1742. TRUE
  1743. );
  1744. if (!NT_SUCCESS(Status)) {
  1745. if (Status != STATUS_OBJECT_NAME_NOT_FOUND) {
  1746. goto QueryValueSecretError;
  1747. }
  1748. Status = STATUS_SUCCESS;
  1749. *CipherValue = NULL;
  1750. return(Status);
  1751. }
  1752. //
  1753. // We successfully read the length of the stored Secret Object value
  1754. // plus header from the Policy Database. Verify that the Secret
  1755. // Object value is either at least as long as a Cipher Value
  1756. // structure header, or is of length 0.
  1757. //
  1758. if ( !LsapDsIsWriteDs( SecretHandle ) &&
  1759. DbCipherValueLength < sizeof (LSAP_CR_CIPHER_VALUE ) ) {
  1760. if (DbCipherValueLength == 0) {
  1761. goto QueryValueSecretFinish;
  1762. }
  1763. Status = STATUS_INTERNAL_DB_ERROR;
  1764. goto QueryValueSecretError;
  1765. }
  1766. //
  1767. // Allocate memory for reading the specified Value of the Secret object.
  1768. // This value is stored in the Policy Database in the form of a
  1769. // Self-Relative Value structure. The Value Buffer part is encrypted.
  1770. //
  1771. DbCipherValue = MIDL_user_allocate(DbCipherValueLength);
  1772. if (DbCipherValue == NULL) {
  1773. Status = STATUS_INSUFFICIENT_RESOURCES;
  1774. goto QueryValueSecretError;
  1775. }
  1776. //
  1777. // Read the specified Policy-database-encrypted Value attribute.
  1778. //
  1779. Status = LsapDbReadAttributeObjectEx(
  1780. SecretHandle,
  1781. ValueIndex,
  1782. DbCipherValue,
  1783. &DbCipherValueLength,
  1784. TRUE
  1785. );
  1786. if (!NT_SUCCESS(Status)) {
  1787. goto QueryValueSecretError;
  1788. }
  1789. //
  1790. // If we are not reading from the DS, the data is encrypted
  1791. //
  1792. if ( !LsapDsIsWriteDs( SecretHandle ) ) {
  1793. PLSAP_CR_CIPHER_KEY KeyToUse = LsapDbCipherKey;
  1794. BOOLEAN SP4Encrypted = FALSE;
  1795. //
  1796. // Verify that Lengths in returned header are consistent
  1797. // and also match returned data length - header size.
  1798. //
  1799. if (DbCipherValue->Length > DbCipherValue->MaximumLength) {
  1800. Status = STATUS_INTERNAL_DB_ERROR;
  1801. goto QueryValueSecretError;
  1802. }
  1803. if ((DbCipherValue->Length + (ULONG) sizeof(LSAP_CR_CIPHER_VALUE)) !=
  1804. DbCipherValueLength) {
  1805. Status = STATUS_INTERNAL_DB_ERROR;
  1806. goto QueryValueSecretError;
  1807. }
  1808. //
  1809. // If the string length is 0, something is wrong.
  1810. //
  1811. if (DbCipherValue->Length == 0) {
  1812. goto QueryValueSecretError;
  1813. }
  1814. //
  1815. // Store pointer to Value buffer in the Value structure. This pointer
  1816. // points just after the header. Then decrypt the Value using the
  1817. // LSA Database Cipher Key and encrypt the result using the Session Key.
  1818. //
  1819. DbCipherValue->Buffer = (PUCHAR)(DbCipherValue + 1);
  1820. if ( FLAG_ON( DbCipherValue->MaximumLength, LSAP_DB_SECRET_SP4_SYSKEY_ENCRYPTED) ) {
  1821. DbCipherValue->MaximumLength &= ~LSAP_DB_SECRET_SP4_SYSKEY_ENCRYPTED;
  1822. if ( LsapDbSP4SecretCipherKey ) {
  1823. KeyToUse = LsapDbSP4SecretCipherKey;
  1824. SP4Encrypted = TRUE;
  1825. } else {
  1826. //
  1827. // This was encrypted using SP4 syskey, but now we don't have it... We're in trouble
  1828. //
  1829. Status = STATUS_INTERNAL_ERROR;
  1830. goto QueryValueSecretError;
  1831. }
  1832. }
  1833. if ( FLAG_ON( DbCipherValue->MaximumLength, LSAP_DB_SECRET_WIN2K_SYSKEY_ENCRYPTED) ) {
  1834. DbCipherValue->MaximumLength &= ~LSAP_DB_SECRET_WIN2K_SYSKEY_ENCRYPTED;
  1835. if ( LsapDbSecretCipherKeyRead ) {
  1836. KeyToUse = LsapDbSecretCipherKeyRead;
  1837. ASSERT(!SP4Encrypted);
  1838. } else {
  1839. //
  1840. // This was encrypted using syskey, but now we don't have it... We're in trouble
  1841. //
  1842. Status = STATUS_INTERNAL_ERROR;
  1843. goto QueryValueSecretError;
  1844. }
  1845. }
  1846. Status = LsapCrDecryptValue(
  1847. DbCipherValue,
  1848. KeyToUse,
  1849. &ClearValue
  1850. );
  1851. if (!NT_SUCCESS(Status)) {
  1852. goto QueryValueSecretError;
  1853. }
  1854. } else {
  1855. ClearValue = MIDL_user_allocate( sizeof( LSAP_CR_CLEAR_VALUE ) + DbCipherValueLength );
  1856. if ( ClearValue == NULL ) {
  1857. Status = STATUS_INSUFFICIENT_RESOURCES;
  1858. goto QueryValueSecretError;
  1859. } else {
  1860. ClearValue->Length = DbCipherValueLength;
  1861. ClearValue->MaximumLength = DbCipherValueLength;
  1862. ClearValue->Buffer = ( PUCHAR )(ClearValue+1);
  1863. RtlCopyMemory( ClearValue->Buffer,
  1864. DbCipherValue,
  1865. DbCipherValueLength );
  1866. }
  1867. }
  1868. //
  1869. // If the client is non-Trusted, encrypt the value with the Session
  1870. // Key, otherwise, leave it unchanged.
  1871. //
  1872. if (!InternalHandle->Trusted) {
  1873. Status = LsapCrEncryptValue(
  1874. ClearValue,
  1875. SessionKey,
  1876. &OutputCipherValue
  1877. );
  1878. //
  1879. // Bug 574002: don't leave the cleartext value lying around
  1880. //
  1881. RtlSecureZeroMemory( ClearValue->Buffer, ClearValue->Length );
  1882. if (!NT_SUCCESS(Status)) {
  1883. goto QueryValueSecretError;
  1884. }
  1885. } else {
  1886. //
  1887. // Trusted clients get a clear-text block back.
  1888. // The block contains both the header and the text.
  1889. //
  1890. OutputCipherValue = (PLSAP_CR_CIPHER_VALUE)(ClearValue);
  1891. }
  1892. QueryValueSecretFinish:
  1893. //
  1894. // If necessary, free memory allocated for the Db-encrypted Secret
  1895. // object Value read from the Policy Database.
  1896. //
  1897. if (DbCipherValue != NULL) {
  1898. LsapCrFreeMemoryValue( DbCipherValue );
  1899. }
  1900. //
  1901. // If necessary, free memory allocated for the Decrypted Value.
  1902. // Trusted client's get a pointer to ClearValue back, so don't
  1903. // free it in this case.
  1904. //
  1905. if ( !InternalHandle->Trusted && ClearValue != NULL ) {
  1906. LsapCrFreeMemoryValue( ClearValue );
  1907. }
  1908. //
  1909. // Return pointer to Cipher Value (Clear Value for trusted clients) or
  1910. // NULL.
  1911. //
  1912. *CipherValue = OutputCipherValue;
  1913. return(Status);
  1914. QueryValueSecretError:
  1915. //
  1916. // If necessary, free memory allocated for the Secret object value
  1917. // after re-encryption for return to the Client.
  1918. //
  1919. if (OutputCipherValue != NULL) {
  1920. LsapCrFreeMemoryValue( OutputCipherValue );
  1921. }
  1922. goto QueryValueSecretFinish;
  1923. }
  1924. NTSTATUS
  1925. LsaIEnumerateSecrets(
  1926. IN LSAPR_HANDLE PolicyHandle,
  1927. IN OUT PLSA_ENUMERATION_HANDLE EnumerationContext,
  1928. OUT PVOID *Buffer,
  1929. IN ULONG PreferedMaximumLength,
  1930. OUT PULONG CountReturned
  1931. )
  1932. /*++
  1933. Routine Description:
  1934. This service returns information about Secret objects. Since there
  1935. may be more information than can be returned in a single call of the
  1936. routine, multiple calls can be made to get all of the information.
  1937. To support this feature, the caller is provided with a handle that
  1938. can be used across calls to the API. On the initial call,
  1939. EnumerationContext should point to a variable that has been
  1940. initialized to 0.
  1941. Arguments:
  1942. PolicyHandle - Trusted handle to an open Policy Object.
  1943. EnumerationContext - Zero-based index at which to start the enumeration.
  1944. Buffer - Receives a pointer to a buffer containing information for
  1945. one or more Secret objects. This information is an array of
  1946. structures of type UNICODE_STRING, with each entry providing the
  1947. name of a single Secret object. When this information is no
  1948. longer needed, it must be released using MIDL_user_free.
  1949. PreferedMaximumLength - Prefered maximum length of the returned
  1950. data (in 8-bit bytes). This is not a hard upper limit but
  1951. serves as a guide. Due to data conversion between systems
  1952. with different natural data sizes, the actual amount of data
  1953. returned may be greater than this value.
  1954. CountReturned - Numer of entries returned.
  1955. Return Values:
  1956. NTSTATUS - Standard Nt Result Code.
  1957. STATUS_SUCCESS - The call completed successfully.
  1958. STATUS_NO_MORE_ENTRIES - No entries have been returned because
  1959. there are no more.
  1960. --*/
  1961. {
  1962. NTSTATUS Status;
  1963. LSAP_DB_NAME_ENUMERATION_BUFFER RegEnumerationBuffer, DsEnumerationBuffer;
  1964. LSAP_DB_NAME_ENUMERATION_BUFFER DomainEnumerationBuffer, *CurrentEnumerationBuffer = NULL;
  1965. PUNICODE_STRING SecretNames = NULL;
  1966. BOOLEAN Locked = FALSE;
  1967. ULONG MaxLength, Entries, Context, Relative = 0;
  1968. LSA_ENUMERATION_HANDLE LocalEnumerationContext;
  1969. //
  1970. // If no Enumeration Structure is provided, return an error.
  1971. //
  1972. if ( !ARGUMENT_PRESENT(Buffer) ||
  1973. !ARGUMENT_PRESENT(EnumerationContext) ) {
  1974. return(STATUS_INVALID_PARAMETER);
  1975. }
  1976. LsapDsDebugOut(( DEB_FTRACE, "LsaIEnumerateSecrets\n" ));
  1977. //
  1978. // Initialize the internal Lsa Database Enumeration Buffers, and
  1979. // the provided Enumeration Buffer to NULL.
  1980. //
  1981. RegEnumerationBuffer.EntriesRead = 0;
  1982. RegEnumerationBuffer.Names = NULL;
  1983. DsEnumerationBuffer.EntriesRead = 0;
  1984. DsEnumerationBuffer.Names = NULL;
  1985. DomainEnumerationBuffer.EntriesRead = 0;
  1986. DomainEnumerationBuffer.Names = NULL;
  1987. *Buffer = NULL;
  1988. Context = *((PULONG)EnumerationContext);
  1989. //
  1990. // Acquire the Lsa Database lock. Verify that the connection handle is
  1991. // valid, is of the expected type and has all of the desired accesses
  1992. // granted. Reference the handle.
  1993. //
  1994. Status = LsapDbReferenceObject(
  1995. PolicyHandle,
  1996. POLICY_VIEW_LOCAL_INFORMATION,
  1997. PolicyObject,
  1998. SecretObject,
  1999. LSAP_DB_LOCK |
  2000. LSAP_DB_READ_ONLY_TRANSACTION |
  2001. LSAP_DB_NO_DS_OP_TRANSACTION
  2002. );
  2003. if (NT_SUCCESS(Status)) {
  2004. Locked = TRUE;
  2005. //
  2006. // Limit the enumeration length except for trusted callers
  2007. //
  2008. if ( !((LSAP_DB_HANDLE) PolicyHandle)->Trusted &&
  2009. (PreferedMaximumLength > LSA_MAXIMUM_ENUMERATION_LENGTH)
  2010. ) {
  2011. MaxLength = LSA_MAXIMUM_ENUMERATION_LENGTH;
  2012. } else {
  2013. MaxLength = PreferedMaximumLength;
  2014. }
  2015. //
  2016. // Call general enumeration routine. This will return an array
  2017. // of names of secrets.
  2018. //
  2019. //
  2020. // Start with the Ds
  2021. //
  2022. Status = LsapDsEnumerateSecrets( &DsEnumerationBuffer );
  2023. if ( !NT_SUCCESS( Status ) ) {
  2024. goto EnumSecretCleanup;
  2025. }
  2026. if ( Context < DsEnumerationBuffer.EntriesRead ) {
  2027. CurrentEnumerationBuffer = &DsEnumerationBuffer;
  2028. } else {
  2029. Relative = DsEnumerationBuffer.EntriesRead;
  2030. //
  2031. // Try the trusted domain ones
  2032. //
  2033. Status = LsapDsEnumerateTrustedDomainsAsSecrets( &DomainEnumerationBuffer );
  2034. if ( !NT_SUCCESS( Status ) ) {
  2035. goto EnumSecretCleanup;
  2036. }
  2037. if ( Context < Relative + DomainEnumerationBuffer.EntriesRead) {
  2038. CurrentEnumerationBuffer = &DomainEnumerationBuffer;
  2039. } else {
  2040. if ( !LsaDsStateInfo.UseDs ) {
  2041. Relative += DomainEnumerationBuffer.EntriesRead;
  2042. LocalEnumerationContext = Context - Relative;
  2043. Status = LsapDbEnumerateNames(
  2044. PolicyHandle,
  2045. SecretObject,
  2046. &LocalEnumerationContext,
  2047. &RegEnumerationBuffer,
  2048. MaxLength
  2049. );
  2050. if ( !NT_SUCCESS( Status ) ) {
  2051. goto EnumSecretCleanup;
  2052. }
  2053. CurrentEnumerationBuffer = &RegEnumerationBuffer;
  2054. } else {
  2055. *CountReturned = 0;
  2056. Status = STATUS_NO_MORE_ENTRIES;
  2057. goto EnumSecretCleanup;
  2058. }
  2059. }
  2060. }
  2061. //
  2062. // At this point:
  2063. //
  2064. // SUCCESS -> Some names are being returned (may or
  2065. // may not be additional names to be retrieved
  2066. // in future calls).
  2067. //
  2068. // NO_MORE_ENTRIES -> There are NO names to return
  2069. // for this or any future call.
  2070. //
  2071. if (NT_SUCCESS(Status)) {
  2072. //
  2073. // Return the number of entries read. Note that the Enumeration Buffer
  2074. // returned from LsapDbEnumerateNames is expected to be non-null
  2075. // in all non-error cases.
  2076. //
  2077. ASSERT(CurrentEnumerationBuffer->EntriesRead != 0);
  2078. //
  2079. // Now copy the output array of Unicode Strings for the caller.
  2080. // Memory for the array and the Unicode Buffers is allocated via
  2081. // MIDL_user_allocate.
  2082. //
  2083. Status = LsapRpcCopyUnicodeStrings(
  2084. NULL,
  2085. CurrentEnumerationBuffer->EntriesRead,
  2086. &SecretNames,
  2087. CurrentEnumerationBuffer->Names
  2088. );
  2089. }
  2090. if ( NT_SUCCESS( Status ) ) {
  2091. *(PULONG)EnumerationContext += CurrentEnumerationBuffer->EntriesRead;
  2092. }
  2093. }
  2094. //
  2095. // Fill in returned Enumeration Structure, returning 0 or NULL for
  2096. // fields in the error case.
  2097. //
  2098. *Buffer = SecretNames;
  2099. if (NULL!=CurrentEnumerationBuffer)
  2100. {
  2101. *CountReturned = CurrentEnumerationBuffer->EntriesRead;
  2102. }
  2103. else
  2104. {
  2105. *CountReturned = 0;
  2106. }
  2107. EnumSecretCleanup:
  2108. //
  2109. // Dereference retains current status value unless
  2110. // error occurs.
  2111. //
  2112. if ( Locked ) {
  2113. LsapDbDereferenceObject(
  2114. &PolicyHandle,
  2115. PolicyObject,
  2116. SecretObject,
  2117. LSAP_DB_LOCK |
  2118. LSAP_DB_READ_ONLY_TRANSACTION |
  2119. LSAP_DB_NO_DS_OP_TRANSACTION,
  2120. (SECURITY_DB_DELTA_TYPE) 0,
  2121. Status
  2122. );
  2123. }
  2124. //
  2125. // Free the allocated memory
  2126. //
  2127. LsapDbFreeEnumerationBuffer( &DomainEnumerationBuffer );
  2128. LsapDbFreeEnumerationBuffer( &DsEnumerationBuffer );
  2129. LsapDbFreeEnumerationBuffer( &RegEnumerationBuffer );
  2130. LsapDsDebugOut(( DEB_FTRACE, "LsaIEnumerateSecrets: 0x%lx\n", Status ));
  2131. return(Status);
  2132. }
  2133. NTSTATUS
  2134. LsaISetTimesSecret(
  2135. IN LSAPR_HANDLE SecretHandle,
  2136. IN PLARGE_INTEGER CurrentValueSetTime,
  2137. IN PLARGE_INTEGER OldValueSetTime
  2138. )
  2139. /*++
  2140. Routine Description:
  2141. This service is used to set the times associated with a Secret object.
  2142. This allows the times of secrets to be set to what they are on the
  2143. Primary Domain Controller (PDC) involved in an LSA Database replication
  2144. rather than being set to the time at which the Secret object is
  2145. created on a Backup Domain Controller (BDC) being replicated to.
  2146. Arguments:
  2147. SecretHandle - Trusted Handle to an open secret object. This will
  2148. have been obtained via a call to LsaCreateSecret() or LsaOpenSecret()
  2149. on which a Trusted Policy Handle was specified.
  2150. CurrentValueSetTime - The date and time to set for the date and time
  2151. at which the Current Value of the Secret object was set.
  2152. OldValueSetTime - The date and time to set for the date and time
  2153. at which the Old Value of the Secret object was set.
  2154. Return Values:
  2155. NTSTATUS - Standard Nt Result Code
  2156. STATUS_SUCCESS - The call completed successfully.
  2157. STATUS_ACCESS_DENIED - The supplied SecretHandle is not Trusted.
  2158. STATUS_INVALID_HANDLE - The supplied SecretHandle is not
  2159. a valid habdle to a Secret Object.
  2160. --*/
  2161. {
  2162. NTSTATUS Status;
  2163. LSAP_DB_HANDLE Handle = (LSAP_DB_HANDLE) SecretHandle;
  2164. BOOLEAN ObjectReferenced = FALSE;
  2165. //
  2166. // Verify that both Times are specified.
  2167. //
  2168. Status = STATUS_INVALID_PARAMETER;
  2169. if (!ARGUMENT_PRESENT( CurrentValueSetTime )) {
  2170. goto SetTimesSecretError;
  2171. }
  2172. if (!ARGUMENT_PRESENT( CurrentValueSetTime )) {
  2173. goto SetTimesSecretError;
  2174. }
  2175. //
  2176. // Acquire the Lsa Database lock. Verify that the Secret Object handle is
  2177. // valid, is of the expected type and has all of the desired accesses
  2178. // granted. Reference the handle and open a database transaction.
  2179. //
  2180. Status = LsapDbReferenceObject(
  2181. SecretHandle,
  2182. SECRET_SET_VALUE,
  2183. SecretObject,
  2184. SecretObject,
  2185. LSAP_DB_LOCK | LSAP_DB_START_TRANSACTION | LSAP_DB_TRUSTED |
  2186. LSAP_DB_NO_DS_OP_TRANSACTION
  2187. );
  2188. if (!NT_SUCCESS(Status)) {
  2189. goto SetTimesSecretError;
  2190. }
  2191. ObjectReferenced = TRUE;
  2192. //
  2193. // See if it's a secret in the Ds, since Ds replication will do the right thing
  2194. // with the time stamps
  2195. //
  2196. if ( LsapDsIsWriteDs( SecretHandle ) ) {
  2197. goto SetTimesSecretFinish;
  2198. }
  2199. //
  2200. // Set the time at which the Current Secret value was last updated
  2201. // to the specified value.
  2202. //
  2203. Status = LsapDbWriteAttributeObject(
  2204. SecretHandle,
  2205. &LsapDbNames[CupdTime],
  2206. CurrentValueSetTime,
  2207. sizeof (LARGE_INTEGER)
  2208. );
  2209. if (!NT_SUCCESS(Status)) {
  2210. goto SetTimesSecretError;
  2211. }
  2212. //
  2213. // Set the time at which the Old Secret value was last updated
  2214. // to the specified value.
  2215. //
  2216. Status = LsapDbWriteAttributeObject(
  2217. SecretHandle,
  2218. &LsapDbNames[OupdTime],
  2219. OldValueSetTime,
  2220. sizeof (LARGE_INTEGER)
  2221. );
  2222. if (!NT_SUCCESS(Status)) {
  2223. goto SetTimesSecretError;
  2224. }
  2225. SetTimesSecretFinish:
  2226. //
  2227. // If necessary, dereference the Secret object, close the database
  2228. // transaction, notify the LSA Database Replicator of the change and
  2229. // release the LSA Database lock and return.
  2230. //
  2231. if (ObjectReferenced) {
  2232. Status = LsapDbDereferenceObject(
  2233. &SecretHandle,
  2234. SecretObject,
  2235. SecretObject,
  2236. LSAP_DB_LOCK | LSAP_DB_FINISH_TRANSACTION |
  2237. LSAP_DB_NO_DS_OP_TRANSACTION,
  2238. SecurityDbChange,
  2239. Status
  2240. );
  2241. }
  2242. return(Status);
  2243. SetTimesSecretError:
  2244. goto SetTimesSecretFinish;
  2245. }
  2246. NTSTATUS
  2247. LsapDbGetScopeSecret(
  2248. IN PLSAPR_UNICODE_STRING SecretName,
  2249. OUT PBOOLEAN GlobalSecret
  2250. )
  2251. /*++
  2252. Routine Description:
  2253. This function checks the scope of a Secret name. Secrets have either
  2254. Global or Local Scope.
  2255. Global Secrets are Secrets that are normally present on all DC's for a
  2256. Domain. They are replicated from PDC's to BDC's. On BDC's, only a
  2257. Trusted Client such as a replicator can create, update or delete Global
  2258. Secrets. Global Secrets are identified as Secrets whose name begins
  2259. with a designated prefix.
  2260. Local Secrets are Secrets that are private to a specific machine. They
  2261. are not replicated. Normal non-trusted clients may create, update or
  2262. delete Local Secrets. Local Secrets are idientified as Secrets whose
  2263. name does not begin with a designated prefix.
  2264. Arguments:
  2265. SecretName - Pointer to Unicode String containing the name of the
  2266. Secret to be checked.
  2267. GlobalSecret - Receives a Boolean indicating
  2268. Return Values:
  2269. NTSTATUS - Standard Nt Result Code
  2270. STATUS_SUCCESS - The Secret name is valid
  2271. STATUS_INVALID_PARAMETER - The Secret Name is invalid in such a
  2272. way as to prevent scope determination.
  2273. --*/
  2274. {
  2275. NTSTATUS Status = STATUS_SUCCESS;
  2276. UNICODE_STRING GlobalPrefix;
  2277. BOOLEAN OutputGlobalSecret = FALSE;
  2278. //
  2279. // Initialize a Unicode String with the Global Secret name Prefix.
  2280. //
  2281. RtlInitUnicodeString( &GlobalPrefix, LSA_GLOBAL_SECRET_PREFIX );
  2282. //
  2283. // Now check if the given Name has the Global Prefix.
  2284. //
  2285. if (RtlPrefixUnicodeString( &GlobalPrefix, (PUNICODE_STRING) SecretName, TRUE)) {
  2286. OutputGlobalSecret = TRUE;
  2287. }
  2288. *GlobalSecret = OutputGlobalSecret;
  2289. return(Status);
  2290. }
  2291. NTSTATUS
  2292. LsapDbBuildSecretCache(
  2293. )
  2294. /*++
  2295. Routine Description:
  2296. This function builds a cache of Secret Objects. Currently, it is not
  2297. implemented
  2298. Arguments:
  2299. None
  2300. Return Value:
  2301. NTSTATUS - Standard Nt Result Code
  2302. --*/
  2303. {
  2304. NTSTATUS Status = STATUS_SUCCESS;
  2305. return(Status);
  2306. }
  2307. NTSTATUS
  2308. LsapDsEnumerateSecrets(
  2309. IN OUT PLSAP_DB_NAME_ENUMERATION_BUFFER EnumerationBuffer
  2310. )
  2311. /*++
  2312. Routine Description:
  2313. This function enumerates all of the secret objects in the Ds
  2314. Arguments:
  2315. EnumerationBuffer - Enumeration buffer to fill
  2316. Return Value:
  2317. STATUS_SUCCESS - Success
  2318. STATUS_INSUFFICIENT_RESOURCES - A memory allocation failed.
  2319. --*/
  2320. {
  2321. NTSTATUS Status = STATUS_SUCCESS;
  2322. PDSNAME *DsNames = NULL;
  2323. ULONG Items, i, Len;
  2324. PBYTE Buffer;
  2325. PUNICODE_STRING Names = NULL;
  2326. WCHAR RdnStart[ MAX_RDN_SIZE + 1 ];
  2327. ATTRTYP AttrType;
  2328. BOOLEAN ResetStates = FALSE;
  2329. //
  2330. // Just return if the Ds isn't running
  2331. //
  2332. if (!LsapDsWriteDs ) {
  2333. RtlZeroMemory( EnumerationBuffer, sizeof( LSAP_DB_NAME_ENUMERATION_BUFFER ) );
  2334. return( Status );
  2335. }
  2336. Status = LsapDsInitAllocAsNeededEx(
  2337. LSAP_DB_READ_ONLY_TRANSACTION |
  2338. LSAP_DB_NO_LOCK |
  2339. LSAP_DB_DS_OP_TRANSACTION,
  2340. SecretObject,
  2341. &ResetStates);
  2342. if ( !NT_SUCCESS( Status )) {
  2343. return Status;
  2344. }
  2345. //
  2346. // First, enumerate all of the secrets
  2347. //
  2348. Status = LsapDsGetListOfSystemContainerItems( CLASS_SECRET,
  2349. &Items,
  2350. &DsNames );
  2351. if ( NT_SUCCESS( Status ) ) {
  2352. Names = MIDL_user_allocate( Items * sizeof( UNICODE_STRING ) );
  2353. if( Names == NULL ) {
  2354. Status = STATUS_INSUFFICIENT_RESOURCES;
  2355. }
  2356. } else if ( Status == STATUS_OBJECT_NAME_NOT_FOUND ) {
  2357. Items = 0;
  2358. Status = STATUS_SUCCESS;
  2359. }
  2360. //
  2361. // Now, we'll start building the appropriate names for each object
  2362. //
  2363. if ( NT_SUCCESS( Status ) ) {
  2364. for ( i = 0; i < Items; i++ ) {
  2365. Status = LsapDsMapDsReturnToStatus( GetRDNInfoExternal(
  2366. DsNames[ i ],
  2367. RdnStart,
  2368. &Len,
  2369. &AttrType ) );
  2370. if ( NT_SUCCESS( Status ) ) {
  2371. PBYTE Buffer;
  2372. //
  2373. // Allocate a buffer to hold the name
  2374. //
  2375. Buffer = MIDL_user_allocate( Len * sizeof( WCHAR ) +
  2376. sizeof( LSA_GLOBAL_SECRET_PREFIX ) );
  2377. if ( Buffer == NULL ) {
  2378. Status = STATUS_INSUFFICIENT_RESOURCES;
  2379. break;
  2380. } else {
  2381. //
  2382. // If the LSA created the global secret, we appended a postfix... Remove
  2383. // that here.
  2384. //
  2385. RdnStart[ Len ] = UNICODE_NULL;
  2386. if ( Len > LSAP_DS_SECRET_POSTFIX_LEN &&
  2387. _wcsicmp( &RdnStart[Len-LSAP_DS_SECRET_POSTFIX_LEN],
  2388. LSAP_DS_SECRET_POSTFIX ) == 0 ) {
  2389. Len -= LSAP_DS_SECRET_POSTFIX_LEN;
  2390. RdnStart[ Len ] = UNICODE_NULL;
  2391. UNICODE_NULL;
  2392. }
  2393. RtlCopyMemory( Buffer,
  2394. LSA_GLOBAL_SECRET_PREFIX,
  2395. sizeof( LSA_GLOBAL_SECRET_PREFIX ) );
  2396. RtlCopyMemory( Buffer + sizeof( LSA_GLOBAL_SECRET_PREFIX ) - sizeof(WCHAR),
  2397. RdnStart,
  2398. ( Len + 1 ) * sizeof( WCHAR ) );
  2399. RtlInitUnicodeString( &Names[ i ], (PWSTR)Buffer );
  2400. }
  2401. }
  2402. }
  2403. }
  2404. //
  2405. // Free any allocated memory we no longer need
  2406. //
  2407. if ( DsNames != NULL ) {
  2408. LsapFreeLsaHeap( DsNames );
  2409. }
  2410. if ( !NT_SUCCESS( Status ) ) {
  2411. for ( i = 0 ; i < Items ; i++ ) {
  2412. MIDL_user_free( Names[i].Buffer );
  2413. }
  2414. MIDL_user_free( Names );
  2415. } else {
  2416. EnumerationBuffer->Names = Names;
  2417. EnumerationBuffer->EntriesRead = Items;
  2418. }
  2419. LsapDsDeleteAllocAsNeededEx(
  2420. LSAP_DB_READ_ONLY_TRANSACTION |
  2421. LSAP_DB_NO_LOCK |
  2422. LSAP_DB_DS_OP_TRANSACTION,
  2423. SecretObject,
  2424. ResetStates
  2425. );
  2426. return( Status );
  2427. }
  2428. NTSTATUS
  2429. LsapDsIsSecretDsTrustedDomainForUpgrade(
  2430. IN PUNICODE_STRING SecretName,
  2431. OUT PLSAPR_HANDLE TDObjHandle,
  2432. OUT BOOLEAN *IsTrustedDomainSecret
  2433. )
  2434. /*++
  2435. Routine Description:
  2436. This function will determine if the indicated secret is the global secret for a trust object.
  2437. Arguments:
  2438. SecretName - Name of secret to check
  2439. ObjectInformation - LsaDb information on the object
  2440. Options - Options to use for the access
  2441. DesiredAccess - Access to open the object with
  2442. TDObjHandle - Where the object handle is returned
  2443. IsTrustedDomainSecret - A TRUE is returned here if this secret is indeed a trusted domain
  2444. secret.
  2445. Return Value:
  2446. STATUS_SUCCESS - Success
  2447. STATUS_INSUFFICIENT_RESOURCES - A memory allocation failed
  2448. --*/
  2449. {
  2450. NTSTATUS Status = STATUS_SUCCESS;
  2451. PWSTR pwszSecretName;
  2452. ATTR SearchAttr[2];
  2453. ATTRVAL AttrVal[2];
  2454. ULONG ObjId = CLASS_TRUSTED_DOMAIN;
  2455. PDSNAME FoundName = NULL;
  2456. UNICODE_STRING HandleName;
  2457. LSAP_DB_HANDLE TDHandle;
  2458. LSAP_DB_OBJECT_INFORMATION NewObjInfo;
  2459. ULONG TDONameLength = 0;
  2460. LsapEnterFunc( "LsapDsIsSecretDsTrustedDomain" );
  2461. *IsTrustedDomainSecret = FALSE;
  2462. *TDObjHandle = NULL;
  2463. LsapDsReturnSuccessIfNoDs
  2464. if ( LsaDsStateInfo.DsInitializedAndRunning == FALSE ) {
  2465. LsapDsDebugOut((DEB_ERROR,
  2466. "LsapDsIsSecretDsTrustedDomain: Object %wZ, Ds is not started\n ",
  2467. SecretName ));
  2468. return( Status );
  2469. }
  2470. //
  2471. // Convert the secret name to a TDO name.
  2472. //
  2473. if ( SecretName->Length <= (LSAP_DS_TRUSTED_DOMAIN_SECRET_PREFIX_LENGTH * sizeof(WCHAR)) ) {
  2474. return Status;
  2475. }
  2476. pwszSecretName = SecretName->Buffer + LSAP_DS_TRUSTED_DOMAIN_SECRET_PREFIX_LENGTH;
  2477. LsapDsDebugOut((DEB_TRACE, "Matching secret %ws to trusted domain\n ", pwszSecretName ));
  2478. AttrVal[0].valLen = sizeof( ULONG );
  2479. AttrVal[0].pVal = (PVOID)&ObjId;
  2480. AttrVal[1].valLen = TDONameLength = wcslen(pwszSecretName) * sizeof(WCHAR );
  2481. AttrVal[1].pVal = (PVOID)pwszSecretName;
  2482. SearchAttr[ 0 ].attrTyp = LsapDbDsAttInfo[TrDmName].AttributeId;
  2483. SearchAttr[ 0 ].AttrVal.valCount = 1;
  2484. SearchAttr[ 0 ].AttrVal.pAVal = &AttrVal[1];
  2485. SearchAttr[ 1 ].attrTyp = ATT_OBJECT_CLASS;
  2486. SearchAttr[ 1 ].AttrVal.valCount = 1;
  2487. SearchAttr[ 1 ].AttrVal.pAVal = &AttrVal[0];
  2488. Status = LsapDsSearchUnique( LSAPDS_OP_NO_TRANS,
  2489. LsaDsStateInfo.DsSystemContainer,
  2490. SearchAttr,
  2491. sizeof(SearchAttr) / sizeof(ATTR),
  2492. &FoundName );
  2493. if ( Status == STATUS_SUCCESS ) {
  2494. UNICODE_STRING TDOName;
  2495. //
  2496. // This is a trusted domain, try opening the trusted domain
  2497. //
  2498. TDOName.Buffer = pwszSecretName;
  2499. TDOName.Length = TDOName.MaximumLength = (USHORT) TDONameLength;
  2500. Status = LsapDbOpenTrustedDomainByName(
  2501. NULL, // use global policy handle
  2502. &TDOName,
  2503. TDObjHandle,
  2504. MAXIMUM_ALLOWED,
  2505. LSAP_DB_START_TRANSACTION,
  2506. TRUE ); // Trusted
  2507. *IsTrustedDomainSecret = TRUE;
  2508. LsapFreeLsaHeap( FoundName );
  2509. }
  2510. else if (STATUS_OBJECT_NAME_NOT_FOUND==Status)
  2511. {
  2512. //
  2513. // O.K to not find the object. That means the secret does not
  2514. // correspond to a TDO.
  2515. //
  2516. Status = STATUS_SUCCESS;
  2517. }
  2518. return( Status );
  2519. }
  2520. NTSTATUS
  2521. LsapDsSecretUpgradeRegistryToDs(
  2522. IN BOOLEAN DeleteOnly
  2523. )
  2524. /*++
  2525. Routine Description:
  2526. This routine will move the remaining registry based secrets into the Ds
  2527. NOTE: It is assumed that the database is locked before calling this routine
  2528. Arguments:
  2529. DeleteOnly -- If TRUE, the registry values are deleted following the upgade.
  2530. Return Values:
  2531. STATUS_SUCCESS -- Success
  2532. --*/
  2533. {
  2534. NTSTATUS Status = STATUS_SUCCESS;
  2535. LSA_ENUMERATION_HANDLE EnumContext = 0;
  2536. PBYTE EnumBuffer;
  2537. ULONG Items, i;
  2538. BOOLEAN GlobalSecret;
  2539. LSAPR_HANDLE Secret = NULL , DsSecret;
  2540. PLSAPR_CR_CIPHER_VALUE Current = NULL, Old = NULL ;
  2541. PLSAPR_UNICODE_STRING SecretName;
  2542. BOOLEAN DbLocked = FALSE;
  2543. LSAP_DB_NAME_ENUMERATION_BUFFER NameEnum;
  2544. BOOLEAN IsTrustedDomainSecret = FALSE;
  2545. LSAPR_HANDLE TDObjHandle = NULL;
  2546. BOOLEAN UseDsOld = LsaDsStateInfo.UseDs;
  2547. if ( !LsapDsWriteDs
  2548. && !DeleteOnly ) {
  2549. return( STATUS_SUCCESS );
  2550. }
  2551. ( ( LSAP_DB_HANDLE )LsapPolicyHandle )->Options |= LSAP_DB_HANDLE_UPGRADE;
  2552. //
  2553. // First, enumerate all of the registry based trusted domains
  2554. //
  2555. while ( NT_SUCCESS( Status ) ) {
  2556. LsaDsStateInfo.UseDs = FALSE;
  2557. Status = LsaIEnumerateSecrets( LsapPolicyHandle,
  2558. &EnumContext,
  2559. &EnumBuffer,
  2560. TENMEG,
  2561. &Items );
  2562. LsaDsStateInfo.UseDs = UseDsOld;
  2563. if ( Status == STATUS_SUCCESS || Status == STATUS_MORE_ENTRIES ) {
  2564. for ( i = 0; i < Items; i++ ) {
  2565. Secret = NULL;
  2566. SecretName = &( ( PLSAPR_UNICODE_STRING )EnumBuffer )[ i ];
  2567. Status = LsapDbGetScopeSecret( SecretName,
  2568. &GlobalSecret );
  2569. if ( !NT_SUCCESS( Status ) || !GlobalSecret ) {
  2570. continue;
  2571. }
  2572. //
  2573. // Get the information from the registry for this secret...
  2574. //
  2575. LsaDsStateInfo.UseDs = FALSE;
  2576. Status = LsarOpenSecret( LsapPolicyHandle,
  2577. SecretName,
  2578. MAXIMUM_ALLOWED,
  2579. &Secret );
  2580. if ( DeleteOnly ) {
  2581. if ( NT_SUCCESS( Status ) ) {
  2582. Status = LsarDeleteObject( &Secret );
  2583. if ( !NT_SUCCESS( Status ) ) {
  2584. LsapDsDebugOut(( DEB_UPGRADE,
  2585. "Failed to delete secret (0x%x)\n",
  2586. Status ));
  2587. Status = STATUS_SUCCESS;
  2588. }
  2589. } else {
  2590. LsapDsDebugOut(( DEB_UPGRADE,
  2591. "Failed to open secret to delete it (0x%x)\n",
  2592. Status ));
  2593. Status = STATUS_SUCCESS;
  2594. }
  2595. LsaDsStateInfo.UseDs = UseDsOld;
  2596. } else {
  2597. if ( NT_SUCCESS( Status ) ) {
  2598. Status = LsarQuerySecret( Secret,
  2599. &Current,
  2600. NULL,
  2601. &Old,
  2602. NULL );
  2603. }
  2604. LsaDsStateInfo.UseDs = UseDsOld;
  2605. //
  2606. // Check if the secret is a global secret corresponding
  2607. // to a trusted domain. Note at this point, due to the
  2608. // sequence of the upgrade, we have trusted domain objects
  2609. // in the DS, corresponding to the outbound trusts only
  2610. //
  2611. Status = LsapDsIsSecretDsTrustedDomainForUpgrade(
  2612. (PUNICODE_STRING)SecretName,
  2613. &TDObjHandle,
  2614. &IsTrustedDomainSecret
  2615. );
  2616. //
  2617. // Now, if that worked, write it out to the Ds
  2618. //
  2619. if ( NT_SUCCESS( Status ) ) {
  2620. if ( IsTrustedDomainSecret) {
  2621. TRUSTED_DOMAIN_AUTH_INFORMATION AuthInfo;
  2622. LSA_AUTH_INFORMATION CurAuth,OldAuth;
  2623. //
  2624. // Build the auth information to be written out
  2625. //
  2626. ASSERT(NULL!=Current);
  2627. NtQuerySystemTime(&CurAuth.LastUpdateTime);
  2628. CurAuth.AuthType = TRUST_AUTH_TYPE_CLEAR;
  2629. CurAuth.AuthInfoLength = Current->Length;
  2630. CurAuth.AuthInfo = Current->Buffer;
  2631. AuthInfo.IncomingAuthInfos = 0;
  2632. AuthInfo.IncomingAuthenticationInformation = NULL;
  2633. AuthInfo.IncomingPreviousAuthenticationInformation = NULL;
  2634. AuthInfo.OutgoingAuthInfos = 1;
  2635. AuthInfo.OutgoingAuthenticationInformation = &CurAuth;
  2636. if (NULL!=Old) {
  2637. NtQuerySystemTime(&OldAuth.LastUpdateTime);
  2638. OldAuth.AuthType = TRUST_AUTH_TYPE_CLEAR;
  2639. OldAuth.AuthInfoLength = Old->Length;
  2640. OldAuth.AuthInfo = Old->Buffer;
  2641. AuthInfo.OutgoingPreviousAuthenticationInformation = &OldAuth;
  2642. } else {
  2643. AuthInfo.OutgoingPreviousAuthenticationInformation =NULL;
  2644. }
  2645. Status = LsarSetInformationTrustedDomain(
  2646. TDObjHandle,
  2647. TrustedDomainAuthInformation,
  2648. ( PLSAPR_TRUSTED_DOMAIN_INFO ) &AuthInfo );
  2649. LsapCloseHandle(&TDObjHandle, Status);
  2650. } else {
  2651. //
  2652. // Case of a normal secret
  2653. //
  2654. Status = LsarCreateSecret(
  2655. LsapPolicyHandle,
  2656. SecretName,
  2657. MAXIMUM_ALLOWED,
  2658. &DsSecret );
  2659. if ( NT_SUCCESS( Status ) ) {
  2660. Status = LsarSetSecret( DsSecret,
  2661. Current,
  2662. Old );
  2663. LsapCloseHandle( &DsSecret, Status );
  2664. #if DBG
  2665. if ( NT_SUCCESS( Status ) ) {
  2666. LsapDsDebugOut(( DEB_UPGRADE,
  2667. "Moved Secret %wZ to Ds\n",
  2668. SecretName ));
  2669. }
  2670. #endif
  2671. }
  2672. if ( Status == STATUS_OBJECT_NAME_COLLISION ) {
  2673. Status = STATUS_SUCCESS;
  2674. }
  2675. }
  2676. }
  2677. if (!NT_SUCCESS(Status)) {
  2678. if (!LsapDsIsNtStatusResourceError(Status)) {
  2679. //
  2680. // Log an event log message indicating the failure
  2681. //
  2682. SpmpReportEventU(
  2683. EVENTLOG_ERROR_TYPE,
  2684. LSA_SECRET_UPGRADE_ERROR,
  2685. 0,
  2686. sizeof( ULONG ),
  2687. &Status,
  2688. 1,
  2689. SecretName
  2690. );
  2691. //
  2692. // Continue on all errors excepting resource errors
  2693. //
  2694. Status = STATUS_SUCCESS;
  2695. }
  2696. else
  2697. {
  2698. //
  2699. // Break out of the loop and terminate the upgrade
  2700. //
  2701. if ( Secret ) {
  2702. LsapCloseHandle( &Secret, Status );
  2703. }
  2704. break;
  2705. }
  2706. }
  2707. if ( Secret ) {
  2708. LsapCloseHandle( &Secret, Status );
  2709. }
  2710. }
  2711. }
  2712. LsaIFree_LSAI_SECRET_ENUM_BUFFER ( EnumBuffer, Items );
  2713. }
  2714. }
  2715. if ( Status == STATUS_NO_MORE_ENTRIES ) {
  2716. Status = STATUS_SUCCESS;
  2717. }
  2718. ( ( LSAP_DB_HANDLE )LsapPolicyHandle )->Options &= ~LSAP_DB_HANDLE_UPGRADE;
  2719. return( Status );
  2720. }
  2721. ULONG
  2722. LsapDbGetSecretType(
  2723. IN PLSAPR_UNICODE_STRING SecretName
  2724. )
  2725. /*++
  2726. Routine Description:
  2727. This function checks the type (scope) of a Secret name. Secrets have
  2728. Global, Local, System, or Client Scope.
  2729. Global Secrets are Secrets that are normally present on all DC's for a
  2730. Domain. They are replicated from PDC's to BDC's. On BDC's, only a
  2731. Trusted Client such as a replicator can create, update or delete Global
  2732. Secrets. Global Secrets are identified as Secrets whose name begins
  2733. with a designated prefix.
  2734. Local Secrets are Secrets that cannot be opened/read/set by anyone
  2735. attempting the operation from across the network.
  2736. System Secrets are thos Secrets that never leave the LSA process.
  2737. Examples are netlogon secrets and service controller secrets
  2738. Client Secrets are Secrets that are private to a specific machine. They
  2739. are not replicated. Normal non-trusted clients may create, update or
  2740. delete Local Secrets. Client Secrets are idientified as Secrets whose
  2741. name does not begin with a designated prefix. These were referred to as
  2742. Local Secrets in the NT3.x-4.x timeframe.
  2743. Arguments:
  2744. SecretName - Pointer to Unicode String containing the name of the
  2745. Secret to be checked.
  2746. Return Values:
  2747. SecretType - Mask of flags describing the type of secret
  2748. --*/
  2749. {
  2750. UNICODE_STRING Prefix;
  2751. ULONG i, SecretType = 0;
  2752. LSAP_DB_SECRET_TYPE_LOOKUP SecretTypePrefixLookupTable[ ] = {
  2753. { LSAP_DS_TRUSTED_DOMAIN_SECRET_PREFIX, LSAP_DB_SECRET_GLOBAL|LSAP_DB_SECRET_TRUSTED_DOMAIN },
  2754. { LSA_GLOBAL_SECRET_PREFIX, LSAP_DB_SECRET_GLOBAL },
  2755. { LSA_LOCAL_SECRET_PREFIX, LSAP_DB_SECRET_LOCAL },
  2756. { LSA_MACHINE_SECRET_PREFIX, LSAP_DB_SECRET_SYSTEM },
  2757. { L"_sc_", LSAP_DB_SECRET_SYSTEM }, // Service Controller passwords
  2758. { L"NL$", LSAP_DB_SECRET_SYSTEM }, // Netlogon secrets
  2759. { L"RasDialParams", LSAP_DB_SECRET_LOCAL },
  2760. { L"RasCredentials", LSAP_DB_SECRET_LOCAL }
  2761. };
  2762. LSAP_DB_SECRET_TYPE_LOOKUP SecretTypeNameLookupTable[ ] = {
  2763. { L"$MACHINE.ACC", LSAP_DB_SECRET_LOCAL },
  2764. { L"SAC", LSAP_DB_SECRET_LOCAL },
  2765. { L"SAI", LSAP_DB_SECRET_LOCAL },
  2766. { L"SANSC", LSAP_DB_SECRET_LOCAL }
  2767. };
  2768. //
  2769. // Until we know better, assume a normal secret
  2770. //
  2771. SecretType = LSAP_DB_SECRET_CLIENT;
  2772. for ( i = 0;
  2773. i < sizeof( SecretTypePrefixLookupTable ) / sizeof( LSAP_DB_SECRET_TYPE_LOOKUP );
  2774. i++ ) {
  2775. //
  2776. // Initialize a Unicode String with the Global Secret name Prefix.
  2777. //
  2778. RtlInitUnicodeString( &Prefix, SecretTypePrefixLookupTable[ i ].SecretPrefix );
  2779. //
  2780. // Now check if the given Name has the Global Prefix.
  2781. //
  2782. if ( RtlPrefixUnicodeString( &Prefix, (PUNICODE_STRING)SecretName, TRUE ) ) {
  2783. SecretType |= SecretTypePrefixLookupTable[ i ].SecretType;
  2784. break;
  2785. }
  2786. }
  2787. //
  2788. // If it's not known yet, see if it is one of the full named secrets we know about...
  2789. //
  2790. if ( SecretType == LSAP_DB_SECRET_CLIENT ) {
  2791. for ( i = 0;
  2792. i < sizeof( SecretTypeNameLookupTable ) / sizeof( LSAP_DB_SECRET_TYPE_LOOKUP );
  2793. i++ ) {
  2794. //
  2795. // Initialize a Unicode String with the Global Secret name Prefix.
  2796. //
  2797. RtlInitUnicodeString( &Prefix, SecretTypeNameLookupTable[ i ].SecretPrefix );
  2798. //
  2799. // Now check if the given Name matches our known secret name
  2800. //
  2801. if ( RtlEqualUnicodeString( &Prefix, ( PUNICODE_STRING )SecretName, TRUE ) ) {
  2802. SecretType |= SecretTypeNameLookupTable[ i ].SecretType;
  2803. break;
  2804. }
  2805. }
  2806. }
  2807. return( SecretType );
  2808. }
  2809. NTSTATUS
  2810. LsapDbUpgradeSecretForKeyChange(
  2811. VOID
  2812. )
  2813. {
  2814. NTSTATUS Status = STATUS_SUCCESS;
  2815. LSAPR_HANDLE SecretHandle;
  2816. PLSAPR_CR_CIPHER_VALUE Current, Old;
  2817. LARGE_INTEGER CurrentTime, OldTime;
  2818. LSA_ENUMERATION_HANDLE EnumContext = 0;
  2819. ULONG EnumCount, i;
  2820. PUNICODE_STRING SecretList;
  2821. BOOLEAN LockHeld = FALSE;
  2822. Status = LsapDbReferenceObject( LsapDbHandle,
  2823. 0,
  2824. PolicyObject,
  2825. SecretObject,
  2826. LSAP_DB_LOCK );
  2827. if ( NT_SUCCESS( Status ) ) {
  2828. LockHeld = TRUE;
  2829. }
  2830. while ( Status == STATUS_SUCCESS ) {
  2831. SecretList = NULL;
  2832. Status = LsaIEnumerateSecrets( LsapDbHandle,
  2833. &EnumContext,
  2834. ( PVOID * )&SecretList,
  2835. 2048,
  2836. &EnumCount );
  2837. for ( i = 0; NT_SUCCESS( Status ) && i < EnumCount; i++ ) {
  2838. Status = LsarOpenSecret( LsapDbHandle,
  2839. ( PLSAPR_UNICODE_STRING )&SecretList[ i ],
  2840. SECRET_SET_VALUE | SECRET_QUERY_VALUE,
  2841. &SecretHandle );
  2842. if ( NT_SUCCESS( Status ) ) {
  2843. Status = LsarQuerySecret( SecretHandle,
  2844. &Current,
  2845. &CurrentTime,
  2846. &Old,
  2847. &OldTime );
  2848. if ( NT_SUCCESS( Status ) ) {
  2849. Status = LsapDbSetSecret( SecretHandle,
  2850. Current,
  2851. &CurrentTime,
  2852. Old,
  2853. &OldTime
  2854. #if defined(REMOTE_BOOT)
  2855. ,
  2856. FALSE
  2857. #endif // defined(REMOTE_BOOT)
  2858. );
  2859. LsaIFree_LSAPR_CR_CIPHER_VALUE( Current );
  2860. LsaIFree_LSAPR_CR_CIPHER_VALUE( Old );
  2861. }
  2862. LsapCloseHandle( &SecretHandle, Status );
  2863. }
  2864. //
  2865. // If there was a problem with the secret, press on:
  2866. // we want to convert as many of them as possible.
  2867. //
  2868. // Log an event log message indicating the failure
  2869. //
  2870. if ( !NT_SUCCESS( Status )) {
  2871. SpmpReportEventU(
  2872. EVENTLOG_ERROR_TYPE,
  2873. LSA_SECRET_UPGRADE_ERROR,
  2874. 0,
  2875. sizeof( ULONG ),
  2876. &Status,
  2877. 1,
  2878. &SecretList[ i ]
  2879. );
  2880. }
  2881. Status = STATUS_SUCCESS;
  2882. }
  2883. MIDL_user_free( SecretList );
  2884. }
  2885. if ( Status == STATUS_NO_MORE_ENTRIES ) {
  2886. Status = STATUS_SUCCESS;
  2887. }
  2888. if ( LockHeld ) {
  2889. Status = LsapDbDereferenceObject( &LsapDbHandle,
  2890. PolicyObject,
  2891. SecretObject,
  2892. LSAP_DB_LOCK,
  2893. ( SECURITY_DB_DELTA_TYPE )0,
  2894. Status );
  2895. }
  2896. return( Status );
  2897. }
  2898. NTSTATUS
  2899. NTAPI
  2900. LsaIChangeSecretCipherKey(
  2901. IN PVOID NewSysKey
  2902. )
  2903. /*++
  2904. Routine Description:
  2905. Given a new syskey, creates a new password encryption key and
  2906. re-encrypts all the secrets with it
  2907. Arguments:
  2908. NewSysKey - new syskey
  2909. Return Values:
  2910. NTSTATUS error code
  2911. --*/
  2912. {
  2913. NTSTATUS Status;
  2914. LSAP_DB_ENCRYPTION_KEY NewEncryptionKey;
  2915. LSAP_DB_ATTRIBUTE Attributes[1];
  2916. PLSAP_DB_ATTRIBUTE NextAttribute = &Attributes[0];
  2917. ULONG AttributeCount = 0;
  2918. BOOLEAN SecretsLocked = FALSE;
  2919. LsapDbAcquireLockEx( SecretObject, 0 );
  2920. SecretsLocked = TRUE;
  2921. //
  2922. // Create a new key for secret encryption
  2923. //
  2924. Status = LsapDbGenerateNewKey( &NewEncryptionKey );
  2925. if ( !NT_SUCCESS( Status )) {
  2926. goto Cleanup;
  2927. }
  2928. //
  2929. // Setup the secret cipher key. This key will be used for writing
  2930. // secrets back to the database. The key used for reading will not
  2931. // be changed until all secrets are re-encrypted.
  2932. //
  2933. LsapDbInitializeSecretCipherKeyWrite( &NewEncryptionKey );
  2934. //
  2935. // Now iterate over all secrets on the machine, re-encrypting them
  2936. //
  2937. Status = LsapDbUpgradeSecretForKeyChange();
  2938. if ( !NT_SUCCESS( Status )) {
  2939. goto Error;
  2940. }
  2941. //
  2942. // Now substitute the key used for reading secrets, as they are all
  2943. // encrypted using the new key
  2944. //
  2945. LsapDbInitializeSecretCipherKeyRead( &NewEncryptionKey );
  2946. LsapDbReleaseLockEx( SecretObject, 0 );
  2947. SecretsLocked = FALSE;
  2948. //
  2949. // Encrypt the key with syskey
  2950. //
  2951. LsapDbEncryptKeyWithSyskey(
  2952. &NewEncryptionKey,
  2953. NewSysKey,
  2954. LSAP_SYSKEY_SIZE
  2955. );
  2956. //
  2957. // Now write out the new password encryption key
  2958. //
  2959. LsapDbInitializeAttribute(
  2960. NextAttribute,
  2961. &LsapDbNames[PolSecretEncryptionKey],
  2962. &NewEncryptionKey,
  2963. sizeof( NewEncryptionKey ),
  2964. FALSE
  2965. );
  2966. NextAttribute++;
  2967. AttributeCount++;
  2968. Status = LsapDbReferenceObject(
  2969. LsapDbHandle,
  2970. 0,
  2971. PolicyObject,
  2972. PolicyObject,
  2973. LSAP_DB_LOCK | LSAP_DB_START_TRANSACTION
  2974. );
  2975. if (NT_SUCCESS(Status)) {
  2976. ASSERT( AttributeCount <= ( sizeof( Attributes ) / sizeof( LSAP_DB_ATTRIBUTE ) ) );
  2977. Status = LsapDbWriteAttributesObject(
  2978. LsapDbHandle,
  2979. Attributes,
  2980. AttributeCount
  2981. );
  2982. //
  2983. // No attributes are replicatable.
  2984. //
  2985. Status = LsapDbDereferenceObject(
  2986. &LsapDbHandle,
  2987. PolicyObject,
  2988. PolicyObject,
  2989. (LSAP_DB_LOCK |
  2990. LSAP_DB_FINISH_TRANSACTION |
  2991. LSAP_DB_OMIT_REPLICATOR_NOTIFICATION ),
  2992. SecurityDbChange,
  2993. Status
  2994. );
  2995. }
  2996. //
  2997. // ISSUE-markpu-2001/06/27
  2998. // If something went wrong and we could not write the password encryption key
  2999. // out, Should we attempt to revert all secrets back to their original state?
  3000. //
  3001. Cleanup:
  3002. if ( SecretsLocked ) {
  3003. LsapDbReleaseLockEx( SecretObject, 0 );
  3004. }
  3005. return Status;
  3006. Error:
  3007. ASSERT( !NT_SUCCESS( Status ));
  3008. goto Cleanup;
  3009. }