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.

5227 lines
157 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. dbobject.c
  5. Abstract:
  6. Local Security Authority - LSA Database Public Object Management Routines
  7. This module contains the public routines that perform LSA Database object
  8. manipulation. These routines are exported to the rest of the
  9. LSA, function prototypes of these routines will be found in db.h. These
  10. exported routines present an implementation-independent hierarchic
  11. object-based view of the LSA Database and are used exclusively by the
  12. LSA API. See the Additional Notes further below for a description of
  13. the LSA Database model.
  14. Routines in this module that are private to the object management
  15. function have function prototypes in dbp.h.
  16. Author:
  17. Scott Birrell (ScottBi) August 26, 1991
  18. Environment:
  19. User Mode
  20. Revision History:
  21. Notes on the LSA Database Architecture
  22. OBJECT STRUCTURE
  23. The LSA Database is an hierarchic structure containing "objects" of
  24. several "types". Objects have either a "name" or a Sid depending only
  25. on object type, and may have data stored with them under named
  26. "attributes". The database hierarchy contains a single root object
  27. called the Lsa Database object and having name "Policy". This object
  28. represents the entire LSA Database. Currently, the Lsa Database has a
  29. simple hierarchy consisting of only two levels.
  30. Policy
  31. Account Objects, Trusted Domain Objects, Secret Objects
  32. The Policy object is called a "Container Object" for the other
  33. object types. The attributes of the Policy object house information
  34. that applies generally to the whole database. The single Policy object
  35. has name "Policy".
  36. Account objects represent those user accounts which are treated specially
  37. on the local system, but not necessarily so on other systems. Such
  38. accounts may have additional privileges, or system quotas for example.
  39. Account objects are referenced by Sid.
  40. TrustedDomain objects describe domains which the system has a trust
  41. relationship with. These objects are referenced by Sid.
  42. Secret Objects are named entities containing information that is protected
  43. in some way. Secret objects are referenced by name.
  44. OBJECT ACCESS AND DATABASE SECURITY
  45. Each object in the LSA Database is protected by a Security Descriptor which
  46. contains a Discretionary Access Control List (DACL) defining which groups
  47. can access the object and in which ways. Before an object can be
  48. accessed, it must first be "opened" with the desired accesses requested
  49. that are needed to perform the desired operations on the object. Opening
  50. an object returns a "handle" to the object. This handle may then be
  51. specified on Lsa services that access the object. After use, the handle
  52. to the object should then be "closed". Closing the handle renders it
  53. invalid.
  54. CONCURRENCY OF ACCESS
  55. More than one handle may be open to an object concurrently, possibly with
  56. different accesses granted.
  57. PERMANENCY OF OBJECTS
  58. All LSA Database objects are backed by non-volatile storage media, that is,
  59. they remain in existence until deleted via the LsaDelete() service.
  60. The Policy object cannot be deleted and the single object of this type cannot
  61. be created via the public LSA service interface.
  62. Objects will not be deleted while there are open handles to them.
  63. When access to an object is no longer required, the handle should be
  64. "closed".
  65. DATABASE DESIGN
  66. The LSA Database is of an hierarchic design permitting future extension.
  67. Currently the database has the following simple hierarchy:
  68. Policy Object (name = Policy)
  69. Account Objects TrustedDomain Objects Secret Objects
  70. The single object of type Policy is at the topmost level and serves as
  71. a parent or "container" object for objects of the other three types.
  72. Since named objects of different types may potentially reside in the
  73. same container object in the future, an object is referenced uniquely
  74. only if the object name and type together with the identity of its
  75. container object (currently always the Policy object) are known.
  76. To implement this kind of reference easily, objects of the same type
  77. are held within a "classifying directory" which has a name derived
  78. from the object's type as follows:
  79. Object Type Containing Directory Name
  80. Policy Not required
  81. Account Accounts
  82. TrustedDomain Domains
  83. Secret Secrets
  84. IMPLEMENTATION NOTES
  85. The LSA Database is currently implemented as a subtree of the Configuration
  86. Registry. This subtree has the following form
  87. \Policy\Accounts\<account_object_Rid>\<account_object_attribute_name>
  88. \Domains\<trusted_domain_Rid>\<trus_domain_object_attribute_name>
  89. \Secrets\<secret_name>\<secret_object_attribute_name>
  90. \<policy_object_attribute_name>
  91. where each item between \..\ is the name of a Registry Key and
  92. "Rid" is a character name made out of the Relative Id (lowest
  93. subauthority extracted from the object's Sid). Named object attributes
  94. can have binary data "values".
  95. --*/
  96. #include <lsapch2.h>
  97. #include "dbp.h"
  98. // #include "adtp.h"
  99. #include <accctrl.h>
  100. #include <sertlp.h>
  101. NTSTATUS
  102. LsapDbOpenObject(
  103. IN PLSAP_DB_OBJECT_INFORMATION ObjectInformation,
  104. IN ACCESS_MASK DesiredAccess,
  105. IN ULONG Options,
  106. OUT PLSAPR_HANDLE ObjectHandle
  107. )
  108. /*++
  109. Routine Description:
  110. This function opens an existing object in the LSA Database. An error
  111. is returned if the object does not already exist. The LSA Database must
  112. be already locked when calling this function and any container handle
  113. must have been validated as having the necessary access for creation
  114. of an object of the given type.
  115. Arguments:
  116. ObjectInformation - Pointer to information describing this object. The
  117. following information items must be specified:
  118. o Object Type Id
  119. o Object Logical Name (as ObjectAttributes->ObjectName, a pointer to
  120. a Unicode string)
  121. o Container object handle (for any object except the root Policy object).
  122. o Object Sid (if any)
  123. All other fields in ObjectAttributes portion of ObjectInformation
  124. such as SecurityDescriptor are ignored.
  125. DesiredAccess - Specifies the Desired accesses to the Lsa object
  126. Options - Specifies optional additional actions to be taken:
  127. LSAP_DB_TRUSTED - A trusted handle is wanted regardless of the trust
  128. status of any container handle provided in ObjectInformation.
  129. LSAP_DB_OMIT_REPLICATOR_NOTIFICATION - Omit replicator notification
  130. on object updates. This flag will be stored in the handle
  131. created for the object and retrieved when committing an update
  132. to the object via LsapDbDereferenceObject().
  133. ObjectHandle - Receives the handle to the object.
  134. Return Value:
  135. NTSTATUS - Standard NT status code
  136. STATUS_INVALID_PARAMETER - One or more parameters invalid.
  137. - Invalid syntax of parameters, e.g Sid
  138. - Sid not specified when required for object type
  139. - Name specified when not allowed.
  140. STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources
  141. to complete the request (e.g. memory for reading object's
  142. Security Descriptor).
  143. STATUS_OBJECT_NOT_FOUND - Object does not exist.
  144. --*/
  145. {
  146. NTSTATUS Status;
  147. ULONG SecurityDescriptorLength;
  148. LSAP_DB_HANDLE NewObjectHandle = NULL;
  149. PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
  150. OBJECT_ATTRIBUTES OpenKeyObjectAttributes;
  151. ULONG States = Options & LSAP_DB_STATE_MASK;
  152. ULONG ResetStates = 0;
  153. LSAPR_HANDLE OutputHandle = NULL;
  154. LSAP_DB_HANDLE InternalOutputHandle = NULL;
  155. PSECURITY_DESCRIPTOR SavedSecurityDescriptor =
  156. ObjectInformation->ObjectAttributes.SecurityDescriptor;
  157. //
  158. // Validate the Object Information parameter.
  159. //
  160. Status = LsapDbVerifyInformationObject( ObjectInformation );
  161. if (!NT_SUCCESS(Status)) {
  162. goto OpenObjectError;
  163. }
  164. //
  165. // Allocate and initialize a handle for the object. The object's
  166. // Registry Key, Logical and Physical Names will be derived from
  167. // the given ObjectInformation and pointers to them will be stored in
  168. // the handle.
  169. //
  170. Status = LsapDbCreateHandle( ObjectInformation,
  171. Options,
  172. LSAP_DB_CREATE_OPEN_EXISTING,
  173. &OutputHandle );
  174. InternalOutputHandle = ( LSAP_DB_HANDLE ) OutputHandle;
  175. if ( !NT_SUCCESS( Status ) ) {
  176. goto OpenObjectError;
  177. }
  178. //
  179. // Now attempt to open the object's Registry Key. Store the Registry
  180. // Key handle in the object's handle.
  181. //
  182. // Avoid this if we're using a cached handle and the key is already open.
  183. //
  184. if ( InternalOutputHandle->KeyHandle == NULL ) {
  185. if ( !LsapDsIsHandleDsHandle( InternalOutputHandle ) ) {
  186. InternalOutputHandle->fWriteDs = FALSE;
  187. Status = LsapRegOpenObject( InternalOutputHandle,
  188. KEY_READ | KEY_WRITE,
  189. &(InternalOutputHandle->KeyHandle)
  190. );
  191. } else {
  192. InternalOutputHandle->fWriteDs = TRUE;
  193. Status = LsapDsOpenObject( InternalOutputHandle,
  194. KEY_READ | KEY_WRITE,
  195. &(InternalOutputHandle->KeyHandle)
  196. );
  197. if ( NT_SUCCESS( Status ) && InternalOutputHandle->ObjectTypeId == PolicyObject) {
  198. Status = LsapRegOpenObject( InternalOutputHandle,
  199. KEY_READ | KEY_WRITE,
  200. &( InternalOutputHandle->KeyHandle ) );
  201. }
  202. }
  203. if (!NT_SUCCESS(Status)) {
  204. InternalOutputHandle->KeyHandle = NULL; // For cleanup purposes
  205. goto OpenObjectError;
  206. }
  207. }
  208. //
  209. // The object exists. Unless access checking is to be bypassed, we
  210. // need to access the object's Security Descriptor and perform an
  211. // access check. The Security Descriptor is stored as the object's
  212. // SecDesc attribute, so we need to read this. First, we must query the
  213. // size of the Security Descriptor to determine how much memory to
  214. // allocate for reading it. The query is done by issuing a read of the
  215. // object's SecDesc subkey with a NULL output buffer and zero size
  216. // specified.
  217. //
  218. if (!(InternalOutputHandle->Trusted)) {
  219. if ( LsapDsIsWriteDs( InternalOutputHandle ) ) {
  220. Status = LsapDsReadObjectSD(
  221. OutputHandle,
  222. &SecurityDescriptor );
  223. } else {
  224. Status = LsapRegReadObjectSD(
  225. OutputHandle,
  226. &SecurityDescriptor );
  227. }
  228. //
  229. // Request the desired accesses and store them in the object's handle.
  230. // granted.
  231. //
  232. if ( NT_SUCCESS( Status ) ) {
  233. ObjectInformation->ObjectAttributes.SecurityDescriptor = SecurityDescriptor;
  234. Status = LsapDbRequestAccessObject(
  235. OutputHandle,
  236. ObjectInformation,
  237. DesiredAccess,
  238. Options
  239. );
  240. }
  241. //
  242. // If the accesses are granted, the open has completed successfully.
  243. // Store the container object handle in the object's handle and
  244. // return the handle to the caller..
  245. //
  246. if (!NT_SUCCESS(Status)) {
  247. //
  248. // Bug #340164: don't disclose information about secret's existence
  249. // by returning "access denied"; map to "not found"
  250. //
  251. if ( Status == STATUS_ACCESS_DENIED &&
  252. LsapGlobalRestrictAnonymous &&
  253. ( ObjectInformation->ObjectTypeId == SecretObject ||
  254. ObjectInformation->ObjectTypeId == AccountObject )&&
  255. ObjectInformation->ObjectAttributes.RootDirectory != NULL &&
  256. ((( LSAP_DB_HANDLE )ObjectInformation->ObjectAttributes.RootDirectory)->Options & LSAP_DB_OPENED_BY_ANONYMOUS )) {
  257. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  258. }
  259. goto OpenObjectError;
  260. }
  261. //
  262. // See if there is an existing identical handle in the cache
  263. //
  264. if ( !LsapDbFindIdenticalHandleInTable( &OutputHandle ) ) {
  265. Status = STATUS_INSUFFICIENT_RESOURCES;
  266. goto OpenObjectError;
  267. }
  268. InternalOutputHandle = ( LSAP_DB_HANDLE ) OutputHandle;
  269. }
  270. *ObjectHandle = OutputHandle;
  271. OpenObjectFinish:
  272. //
  273. // Restore the saved Security Descriptor reference in the object
  274. // information.
  275. //
  276. ObjectInformation->ObjectAttributes.SecurityDescriptor =
  277. SavedSecurityDescriptor;
  278. //
  279. // If necessary, free the memory allocated for the Security Descriptor
  280. //
  281. if (SecurityDescriptor != NULL) {
  282. LsapFreeLsaHeap( SecurityDescriptor );
  283. }
  284. return(Status);
  285. OpenObjectError:
  286. //
  287. // If necessary, free the handle we created.
  288. //
  289. if (OutputHandle != NULL) {
  290. LsapDbDereferenceHandle(OutputHandle, FALSE);
  291. }
  292. goto OpenObjectFinish;
  293. }
  294. NTSTATUS
  295. LsapDbCreateObject(
  296. IN OUT PLSAP_DB_OBJECT_INFORMATION ObjectInformation,
  297. IN ACCESS_MASK DesiredAccess,
  298. IN ULONG CreateDisposition,
  299. IN ULONG Options,
  300. IN OPTIONAL PLSAP_DB_ATTRIBUTE Attributes,
  301. IN OUT ULONG *TypeSpecificAttributeCount,
  302. IN ULONG TypeSpecificAttributeAllocated,
  303. OUT PLSAPR_HANDLE ObjectHandle
  304. )
  305. /*++
  306. Routine Description:
  307. This function creates an object in the LSA Database, together with
  308. the set of attributes, such as Security Descriptor that are common
  309. to all object types. The object will be left in the open state
  310. and the caller may use the returned handle to create the type-
  311. specific attributes.
  312. NOTE: For an object creation, it is the responsibility of the calling
  313. LSA object creation routine to verify that the necessary access to the
  314. container object is granted. That access is dependent on the type of
  315. LSA object being created.
  316. WARNING: The Lsa Database must be in the locked state when this function
  317. is called. No Lsa Database transaction may be pending when
  318. this function is called.
  319. Arguments:
  320. ObjectInformation - Pointer to information describing this object. The
  321. following information items must be specified:
  322. o Object Type Id
  323. o Object Logical Name (as ObjectAttributes->ObjectName, a pointer to
  324. a Unicode string)
  325. o Container object handle (for any object except the root Policy object).
  326. o Object Sid (if any)
  327. All other fields in ObjectAttributes portion of ObjectInformation
  328. such as SecurityDescriptor are ignored.
  329. DesiredAccess - Specifies the Desired accesses to the object.
  330. CreateDisposition - Specifies the Creation Disposition. This is the
  331. action to take depending on whether the object already exists.
  332. LSA_OBJECT_CREATE - Create the object if it does not exist. If
  333. the object already exists, return an error.
  334. LSA_OBJECT_OPEN_IF - Create the object if it does not exist. If
  335. the object already exists, just open it.
  336. Options - Specifies optional information and actions to be taken
  337. LSAP_DB_TRUSTED - A Trusted Handle is wanted regardless of the
  338. Trust status of any container handle provided in
  339. ObjectInformation.
  340. LSAP_DB_OMIT_REPLICATOR_NOTIFICATION - Omit notification of the
  341. object creation to Replicator.
  342. Note, this routine performs a complete database transaction so
  343. there is no option to start one.
  344. Attributes - Optional pointer to an array of attribute
  345. names and values. These are specific to the type of object.
  346. TypeSpecificAttributeCount - Number of elements in the array
  347. referenced by the Attributes parameter. This can be updated
  348. if attributes are added.
  349. TypeSpecificAttributeAllocated -- the number attributes that have been
  350. preallocated in Attributes
  351. ObjectHandle - Receives the handle to the object.
  352. Return Value:
  353. NTSTATUS - Standard Nt Result Code
  354. STATUS_INVALID_PARAMETER - The given Sid is invalid.
  355. STATUS_OBJECT_NAME_EXISTS - An object having the given Sid
  356. already exists and has been opened because LSA_OBJECT_OPEN_IF
  357. disposition has been specified. This is a warning only.
  358. STATUS_OBJECT_NAME_COLLISION - An object having the given Sid
  359. already exists but has not been opened because LSA_OBJECT_CREATE
  360. disposition has been specified. This is an error.
  361. --*/
  362. {
  363. NTSTATUS Status, SecondaryStatus, IgnoreStatus;
  364. OBJECT_ATTRIBUTES OpenKeyObjectAttributes;
  365. ULONG CloseOptions, Index, TrustAttribs = 0, TrustType, TransOptions = 0, EndTransOptions = 0;
  366. BOOLEAN CreatedObject = FALSE;
  367. BOOLEAN OpenedObject = FALSE;
  368. BOOLEAN OpenedTransaction = FALSE;
  369. LSAPR_HANDLE OutputHandle = NULL;
  370. LSAP_DB_HANDLE InternalOutputHandle = (LSAP_DB_HANDLE) OutputHandle;
  371. LSAP_DB_HANDLE ContainerHandle = NULL;
  372. LSAP_DB_OBJECT_TYPE_ID ObjectTypeId = ObjectInformation->ObjectTypeId;
  373. PDSNAME ObjectXRef = NULL;
  374. LsapDsDebugOut(( DEB_FTRACE, "LsapDbCreateObject\n" ));
  375. //
  376. // Sanity check the values
  377. //
  378. ASSERT(*TypeSpecificAttributeCount <= TypeSpecificAttributeAllocated);
  379. //
  380. // Get the container handle
  381. //
  382. ContainerHandle = (LSAP_DB_HANDLE) ObjectInformation->ObjectAttributes.RootDirectory;
  383. //
  384. // Verify the creation disposition.
  385. //
  386. if (((CreateDisposition & ~LSAP_DB_CREATE_VALID_EXTENDED_FLAGS) != LSAP_DB_OBJECT_CREATE) &&
  387. ((CreateDisposition & ~LSAP_DB_CREATE_VALID_EXTENDED_FLAGS) != LSAP_DB_OBJECT_OPEN_IF)) {
  388. Status = STATUS_INVALID_PARAMETER;
  389. goto CreateObjectError;
  390. }
  391. //
  392. // Try to open the object. It is permissible for the object to
  393. // exist already if LSA_OBJECT_OPEN_IF disposition was specified.
  394. //
  395. if ( FLAG_ON( CreateDisposition, LSAP_DB_CREATE_OBJECT_IN_DS ) ) {
  396. Options |= LSAP_DB_OBJECT_SCOPE_DS;
  397. }
  398. Status = LsapDbOpenObject(
  399. ObjectInformation,
  400. DesiredAccess,
  401. Options,
  402. &OutputHandle
  403. );
  404. InternalOutputHandle = (LSAP_DB_HANDLE) OutputHandle;
  405. if (NT_SUCCESS(Status)) {
  406. //
  407. // The object was successfully opened. If LSA_OBJECT_OPEN_IF
  408. // disposition was specified, we're done, otherwise, we
  409. // return a collision error.
  410. //
  411. OpenedObject = TRUE;
  412. if ( (CreateDisposition & ~LSAP_DB_CREATE_VALID_EXTENDED_FLAGS) == LSAP_DB_OBJECT_OPEN_IF) {
  413. Status = STATUS_OBJECT_NAME_EXISTS;
  414. goto CreateObjectFinish;
  415. }
  416. if ((CreateDisposition & ~LSAP_DB_CREATE_VALID_EXTENDED_FLAGS) == LSAP_DB_OBJECT_CREATE ) {
  417. Status = STATUS_OBJECT_NAME_COLLISION;
  418. LsapLogError(
  419. "LsapDbCreateObject: 0x%lx\n", Status
  420. );
  421. goto CreateObjectError;
  422. }
  423. }
  424. //
  425. // The object was not successfully opened. If this is for any
  426. // reason other than that the object was not found, return an error.
  427. //
  428. if (Status != STATUS_OBJECT_NAME_NOT_FOUND) {
  429. goto CreateObjectError;
  430. }
  431. //
  432. // If this is a trusted domain object, and the Ds is installed, let's try and open it
  433. // by Sid as well. If this succeeds, then we'll consider that the object exists, even
  434. // if the names don't match..
  435. //
  436. if ( LsaDsStateInfo.UseDs && ObjectInformation->ObjectTypeId == TrustedDomainObject &&
  437. ObjectInformation->Sid != NULL ) {
  438. Status = LsapDsTrustedDomainSidToLogicalName( ObjectInformation->Sid,
  439. NULL );
  440. if (NT_SUCCESS(Status)) {
  441. //
  442. // The object was successfully opened. If LSA_OBJECT_OPEN_IF
  443. // disposition was specified, we're done, otherwise, we
  444. // return a collision error.
  445. //
  446. if ( (CreateDisposition & ~LSAP_DB_CREATE_VALID_EXTENDED_FLAGS) == LSAP_DB_OBJECT_OPEN_IF) {
  447. Status = STATUS_OBJECT_NAME_EXISTS;
  448. goto CreateObjectFinish;
  449. }
  450. if ((CreateDisposition & ~LSAP_DB_CREATE_VALID_EXTENDED_FLAGS) == LSAP_DB_OBJECT_CREATE ) {
  451. Status = STATUS_OBJECT_NAME_COLLISION;
  452. goto CreateObjectError;
  453. }
  454. }
  455. if (Status != STATUS_OBJECT_NAME_NOT_FOUND) {
  456. goto CreateObjectError;
  457. }
  458. }
  459. //
  460. // The object was not found. Prepare to create it. First, we need to
  461. // check that any maximum limit on the number of objects of this type
  462. // imposed will not be exceeded.
  463. //
  464. Status = LsapDbCheckCountObject(ObjectTypeId);
  465. if (!NT_SUCCESS(Status)) {
  466. goto CreateObjectError;
  467. }
  468. //
  469. // Next we need to create a handle for the new object.
  470. //
  471. if ( ObjectInformation->ObjectTypeId == TrustedDomainObject ) {
  472. ObjectInformation->ObjectTypeId = NewTrustedDomainObject;
  473. }
  474. Status = LsapDbCreateHandle( ObjectInformation,
  475. Options,
  476. LSAP_DB_CREATE_HANDLE_MORPH,
  477. &OutputHandle );
  478. InternalOutputHandle = (LSAP_DB_HANDLE) OutputHandle;
  479. if ( ObjectInformation->ObjectTypeId == NewTrustedDomainObject ) {
  480. ObjectInformation->ObjectTypeId = TrustedDomainObject;
  481. }
  482. if ( !NT_SUCCESS( Status ) ) {
  483. goto CreateObjectError;
  484. }
  485. //
  486. // If this is a Ds object, indicate so in the handle, so that in the
  487. // subsequent call to RequestAccessNewObject, we can properly make the
  488. // determiniation on whether to abort if this is a backup domain controller
  489. //
  490. if ( LsapDsIsHandleDsHandle( InternalOutputHandle ) ) {
  491. LsapDsSetHandleWriteDs( InternalOutputHandle );
  492. }
  493. //
  494. // Verify that the requested accesses can be given to the handle that
  495. // has been opened and grant them if so.
  496. //
  497. Status = LsapDbRequestAccessNewObject(
  498. OutputHandle,
  499. ObjectInformation,
  500. DesiredAccess,
  501. Options
  502. );
  503. if (!NT_SUCCESS(Status)) {
  504. goto CreateObjectError;
  505. }
  506. //
  507. // Open a Registry transaction for creation of the object.
  508. //
  509. if ( ObjectTypeId == TrustedDomainObject ) {
  510. TransOptions |= LSAP_DB_READ_ONLY_TRANSACTION; // Skip the registry transaction
  511. EndTransOptions |= LSAP_DB_READ_ONLY_TRANSACTION;
  512. }
  513. if ( ObjectTypeId == SecretObject && !FLAG_ON( Options, LSAP_DB_OBJECT_SCOPE_DS ) ) {
  514. TransOptions |= LSAP_DB_NO_DS_OP_TRANSACTION;
  515. EndTransOptions |= LSAP_DB_NO_DS_OP_TRANSACTION;
  516. }
  517. if ( ObjectTypeId == PolicyObject ||
  518. ObjectTypeId == AccountObject ) {
  519. TransOptions |= LSAP_DB_NO_DS_OP_TRANSACTION;
  520. EndTransOptions |= LSAP_DB_NO_DS_OP_TRANSACTION;
  521. }
  522. Status = LsapDbOpenTransaction( TransOptions );
  523. if (!NT_SUCCESS(Status)) {
  524. goto CreateObjectError;
  525. }
  526. OpenedTransaction = TRUE;
  527. //
  528. // Add a registry transaction to create the Registry key for the new
  529. // Database object.
  530. //
  531. //
  532. // If we have a Ds name, do a Ds create
  533. //
  534. if ( !LsapDsIsHandleDsHandle( InternalOutputHandle ) ) {
  535. //
  536. // Create it in the registry
  537. //
  538. InternalOutputHandle->fWriteDs = FALSE;
  539. Status = LsapRegCreateObject( &InternalOutputHandle->PhysicalNameU,
  540. ObjectTypeId );
  541. } else {
  542. //
  543. // Don't actually attempt to create an account object
  544. //
  545. if ( InternalOutputHandle->ObjectTypeId != AccountObject) {
  546. Status = LsapDsCreateObject(
  547. &InternalOutputHandle->PhysicalNameDs,
  548. FLAG_ON( ContainerHandle->Options, LSAP_DB_TRUSTED) ?
  549. LSAPDS_CREATE_TRUSTED :
  550. 0,
  551. ObjectTypeId );
  552. if ((STATUS_ACCESS_DENIED == Status)
  553. && (ObjectInformation->ObjectTypeId == TrustedDomainObject)) {
  554. //
  555. // If this is an attempt to create a trust, check to see
  556. // if this request will be granted by a control access
  557. // right.
  558. //
  559. Status = LsapCheckTDOCreationByControlAccess(ObjectInformation,
  560. Attributes,
  561. *TypeSpecificAttributeCount);
  562. if (NT_SUCCESS(Status)) {
  563. //
  564. // Request is allowed, create as trusted, along with
  565. // the default security descriptor
  566. //
  567. Status = LsapDsCreateObject(
  568. &InternalOutputHandle->PhysicalNameDs,
  569. LSAPDS_CREATE_TRUSTED | LSAPDS_CREATE_WITH_SD,
  570. ObjectTypeId );
  571. if (NT_SUCCESS(Status)) {
  572. //
  573. // Adjust the handle access
  574. //
  575. InternalOutputHandle->GrantedAccess = (TRUSTED_READ |
  576. TRUSTED_SET_AUTH |
  577. DELETE);
  578. //
  579. // Modify the attributes on the trust object to
  580. // reflect the fact that this object was created
  581. // via the control access right.
  582. //
  583. Status = LsapUpdateTDOAttributesForCreation(&InternalOutputHandle->PhysicalNameDs,
  584. Attributes,
  585. TypeSpecificAttributeCount,
  586. TypeSpecificAttributeAllocated);
  587. }
  588. }
  589. }
  590. } else {
  591. //
  592. // Since we didn't actually create an object, don't do any notification
  593. //
  594. Options |= LSAP_DB_OMIT_REPLICATOR_NOTIFICATION;
  595. goto CreateObjectReset;
  596. }
  597. }
  598. if (!NT_SUCCESS(Status)) {
  599. goto CreateObjectError;
  600. }
  601. //
  602. // Create the Security Descriptor for the new object. This will be
  603. // stored in Self-Relative form as the value of the SecDesc attribute
  604. // of the new object.
  605. //
  606. Status = LsapDbCreateSDAttributeObject(
  607. OutputHandle,
  608. ObjectInformation
  609. );
  610. if (!NT_SUCCESS(Status)) {
  611. goto CreateObjectError;
  612. }
  613. //
  614. // The self-relative SD returned is not needed here or by callers of
  615. // this routine.
  616. //
  617. if (ObjectInformation->ObjectAttributes.SecurityDescriptor != NULL) {
  618. RtlFreeHeap(
  619. RtlProcessHeap(),
  620. 0,
  621. ObjectInformation->ObjectAttributes.SecurityDescriptor
  622. );
  623. ObjectInformation->ObjectAttributes.SecurityDescriptor = NULL;
  624. }
  625. //
  626. // Write the type-specific attributes (if any) for the object).
  627. //
  628. if (*TypeSpecificAttributeCount != 0) {
  629. Status = LsapDbWriteAttributesObject(
  630. OutputHandle,
  631. Attributes,
  632. *TypeSpecificAttributeCount
  633. );
  634. if (!NT_SUCCESS(Status)) {
  635. goto CreateObjectError;
  636. }
  637. }
  638. CreateObjectReset:
  639. //
  640. // Apply the Registry Transaction to create the object. Note
  641. // that we have to create the object before we can open its
  642. // registry key for placement within the handle.
  643. //
  644. Status = LsapDbResetStates(
  645. OutputHandle,
  646. Options | EndTransOptions | LSAP_DB_FINISH_TRANSACTION,
  647. ObjectTypeId,
  648. SecurityDbNew,
  649. Status
  650. );
  651. OpenedTransaction = FALSE;
  652. if (!NT_SUCCESS(Status)) {
  653. goto CreateObjectError;
  654. }
  655. //
  656. // Increment the count of objects created. It should not have
  657. // changed since we're still holding the LSA Database lock.
  658. // NOTE: Count is decremented on error inside LsapDbDeleteObject()
  659. //
  660. LsapDbIncrementCountObject(ObjectInformation->ObjectTypeId);
  661. CreatedObject = TRUE;
  662. if ( !LsapDsIsWriteDs( OutputHandle ) ) {
  663. //
  664. // The object has now been created. We need to obtain its Registry
  665. // Key handle so that we can save it in the Object Handle.
  666. // Setup Object Attributes structure for opening the Registry key of
  667. // the object. Specify as path the Physical Name of the object, this
  668. // being the path of the object's Registry Key relative to the
  669. // LSA Database root key.
  670. //
  671. InitializeObjectAttributes(
  672. &OpenKeyObjectAttributes,
  673. &InternalOutputHandle->PhysicalNameU,
  674. OBJ_CASE_INSENSITIVE,
  675. LsapDbState.DbRootRegKeyHandle,
  676. NULL
  677. );
  678. //
  679. // Now attempt to open the object's Registry Key. Store the Registry
  680. // Key handle in the object's handle.
  681. //
  682. Status = RtlpNtOpenKey(
  683. (PHANDLE) &InternalOutputHandle->KeyHandle,
  684. KEY_READ | KEY_WRITE,
  685. &OpenKeyObjectAttributes,
  686. 0L
  687. );
  688. if (!NT_SUCCESS(Status)) {
  689. InternalOutputHandle->KeyHandle = NULL;
  690. goto CreateObjectError;
  691. }
  692. }
  693. //
  694. // Add the new object to the in-memory cache (if any). This is done
  695. // after all other actions, so that no removal from the cache is required
  696. // on the error paths. If the object cannot be added to the cache, the
  697. // cache routine automatically disables the cache.
  698. //
  699. if ( ObjectTypeId == AccountObject &&
  700. LsapDbIsCacheSupported( AccountObject ) &&
  701. LsapDbIsCacheValid( AccountObject )) {
  702. IgnoreStatus = LsapDbCreateAccount(
  703. InternalOutputHandle->Sid,
  704. NULL
  705. );
  706. }
  707. CreateObjectFinish:
  708. //
  709. // Return NULL or a handle to the newly created and opened object.
  710. //
  711. *ObjectHandle = OutputHandle;
  712. LsapDsDebugOut(( DEB_FTRACE, "LsapDbCreateObject: 0x%lx\n", Status ));
  713. return(Status);
  714. CreateObjectError:
  715. //
  716. // Cleanup after error. Various variables are set non-null if
  717. // there is cleanup work to do.
  718. //
  719. //
  720. // If necessary, abort the Registry Transaction to create the object
  721. //
  722. if (OpenedTransaction) {
  723. SecondaryStatus = LsapDbResetStates(
  724. OutputHandle,
  725. EndTransOptions | LSAP_DB_FINISH_TRANSACTION,
  726. ObjectTypeId,
  727. (SECURITY_DB_DELTA_TYPE) 0,
  728. Status
  729. );
  730. LsapDbSetStatusFromSecondary( Status, SecondaryStatus );
  731. }
  732. //
  733. // If we opened the object, close it.
  734. //
  735. if (OpenedObject) {
  736. CloseOptions = 0;
  737. SecondaryStatus = LsapDbCloseObject( &OutputHandle, CloseOptions, Status );
  738. if ( Status != SecondaryStatus && !NT_SUCCESS(SecondaryStatus)) {
  739. LsapLogError(
  740. "LsapDbCreateObject: LsapDbCloseObject failed 0x%lx\n",
  741. SecondaryStatus
  742. );
  743. }
  744. OutputHandle = NULL;
  745. InternalOutputHandle = (LSAP_DB_HANDLE) OutputHandle;
  746. } else if (CreatedObject) {
  747. //
  748. // If we created the object, convert its handle into a trusted
  749. // handle and delete it.
  750. //
  751. InternalOutputHandle->Trusted = TRUE;
  752. SecondaryStatus = LsarDelete( OutputHandle );
  753. if (!NT_SUCCESS(SecondaryStatus)) {
  754. LsapLogError(
  755. "LsapDbCreateObject: LsarDeleteObject failed 0x%lx\n",
  756. SecondaryStatus
  757. );
  758. }
  759. } else if (OutputHandle != NULL) {
  760. //
  761. // If we just created the handle, free it.
  762. //
  763. LsapDbDereferenceHandle( OutputHandle, FALSE );
  764. OutputHandle = NULL;
  765. InternalOutputHandle = (LSAP_DB_HANDLE) OutputHandle;
  766. }
  767. goto CreateObjectFinish;
  768. DBG_UNREFERENCED_PARAMETER( CloseOptions );
  769. }
  770. GUID LsapDsTrustedDomainNamePropSet = {0x4886566c,0xaf31,0x11d2,0xb7,0xdf,0x00,0x80,0x5f,0x48,0xca,0xeb};
  771. GUID LsapDsTrustedDomainAuthPropSet = {0x736e4812,0xaf31,0x11d2,0xb7,0xdf,0x00,0x80,0x5f,0x48,0xca,0xeb};
  772. GUID LsapDsTrustedDomainPosixPropSet = {0x9567ca92,0xaf31,0x11d2,0xb7,0xdf,0x00,0x80,0x5f,0x48,0xca,0xeb};
  773. static LSAP_DS_OBJECT_ACCESS_MAP TrustedDomainAccessMap[] = {
  774. { TRUSTED_QUERY_DOMAIN_NAME, ACTRL_DS_READ_PROP, ACCESS_PROPERTY_SET_GUID, &LsapDsTrustedDomainNamePropSet },
  775. { TRUSTED_SET_AUTH, ACTRL_DS_WRITE_PROP, ACCESS_PROPERTY_SET_GUID, &LsapDsTrustedDomainAuthPropSet },
  776. { TRUSTED_QUERY_AUTH, ACTRL_DS_READ_PROP, ACCESS_PROPERTY_SET_GUID, &LsapDsTrustedDomainAuthPropSet },
  777. { TRUSTED_QUERY_POSIX, ACTRL_DS_READ_PROP, ACCESS_PROPERTY_SET_GUID, &LsapDsTrustedDomainPosixPropSet },
  778. { TRUSTED_SET_POSIX, ACTRL_DS_WRITE_PROP, ACCESS_PROPERTY_SET_GUID, &LsapDsTrustedDomainPosixPropSet }
  779. };
  780. #define TrustedDomainAccessMapSize ((sizeof(TrustedDomainAccessMap))/(sizeof(TrustedDomainAccessMap[0])))
  781. static LSAP_DS_OBJECT_ACCESS_MAP TrustedDomainAsSecretAccessMap[] = {
  782. { SECRET_QUERY_VALUE, ACTRL_DS_READ_PROP, ACCESS_PROPERTY_SET_GUID, &LsapDsTrustedDomainAuthPropSet },
  783. { SECRET_SET_VALUE, ACTRL_DS_READ_PROP, ACCESS_PROPERTY_SET_GUID, &LsapDsTrustedDomainAuthPropSet }
  784. };
  785. #define TrustedDomainAsSecretAccessMapSize ((sizeof(TrustedDomainAsSecretAccessMap))/(sizeof(TrustedDomainAsSecretAccessMap[0])))
  786. OBJECT_TYPE_LIST TrustedDomainTypeList[] = {
  787. { ACCESS_OBJECT_GUID, 0, &LsapDsGuidList[ LsapDsGuidTrust ] },
  788. { ACCESS_PROPERTY_SET_GUID,0,&LsapDsTrustedDomainNamePropSet},
  789. { ACCESS_PROPERTY_GUID, 0,&LsapDsGuidList[ LsapDsGuidFlatName ] },
  790. { ACCESS_PROPERTY_GUID, 0,&LsapDsGuidList[ LsapDsGuidSid ] },
  791. { ACCESS_PROPERTY_GUID, 0,&LsapDsGuidList[ LsapDsGuidAttributes ] },
  792. { ACCESS_PROPERTY_GUID, 0,&LsapDsGuidList[ LsapDsGuidDirection ] },
  793. { ACCESS_PROPERTY_GUID, 0,&LsapDsGuidList[ LsapDsGuidPartner] },
  794. { ACCESS_PROPERTY_GUID, 0,&LsapDsGuidList[ LsapDsGuidType ] },
  795. { ACCESS_PROPERTY_SET_GUID, 0, &LsapDsTrustedDomainAuthPropSet},
  796. { ACCESS_PROPERTY_GUID, 0,&LsapDsGuidList[ LsapDsGuidInitialIncoming ] },
  797. { ACCESS_PROPERTY_GUID, 0,&LsapDsGuidList[ LsapDsGuidInitialOutgoing ] },
  798. { ACCESS_PROPERTY_GUID, 0,&LsapDsGuidList[ LsapDsGuidIncoming ] },
  799. { ACCESS_PROPERTY_GUID, 0,&LsapDsGuidList[ LsapDsGuidOutgoing ] },
  800. { ACCESS_PROPERTY_SET_GUID, 0,&LsapDsTrustedDomainPosixPropSet},
  801. { ACCESS_PROPERTY_GUID, 0,&LsapDsGuidList[ LsapDsGuidPosix ] },
  802. };
  803. #define TDTYPE_LIST_SIZE ((sizeof( TrustedDomainTypeList ))/(sizeof( OBJECT_TYPE_LIST )))
  804. GUID LsapDsSecretPropSet = {0x9fa81d6c,0xaf69,0x11d2,0xb7,0xdf,0x00,0x80,0x5f,0x48,0xca,0xeb};
  805. static LSAP_DS_OBJECT_ACCESS_MAP GlobalSecretAccessMap[] = {
  806. { SECRET_QUERY_VALUE, ACTRL_DS_READ_PROP, ACCESS_PROPERTY_SET_GUID, &LsapDsSecretPropSet },
  807. { SECRET_SET_VALUE, ACTRL_DS_WRITE_PROP, ACCESS_PROPERTY_SET_GUID, &LsapDsSecretPropSet }
  808. };
  809. #define GlobalSecretAccessMapSize ( (sizeof(GlobalSecretAccessMap))/(sizeof(GlobalSecretAccessMap[0])))
  810. OBJECT_TYPE_LIST GlobalSecretTypeList[] = {
  811. { ACCESS_OBJECT_GUID, 0, &LsapDsGuidList[ LsapDsGuidSecret ] },
  812. { ACCESS_PROPERTY_SET_GUID, 0, &LsapDsSecretPropSet },
  813. { ACCESS_PROPERTY_SET_GUID, 0, &LsapDsGuidList[LsapDsGuidCurrent] },
  814. { ACCESS_PROPERTY_SET_GUID, 0, &LsapDsGuidList[LsapDsGuidCurrentTime] },
  815. { ACCESS_PROPERTY_SET_GUID, 0, &LsapDsGuidList[LsapDsGuidPrevious] },
  816. { ACCESS_PROPERTY_SET_GUID, 0, &LsapDsGuidList[LsapDsguidPreviousTime] }
  817. };
  818. #define SECRETTYPE_LIST_SIZE ( sizeof( GlobalSecretTypeList ) / sizeof( OBJECT_TYPE_LIST ) )
  819. // generic read
  820. #define LSAP_DS_GENERIC_READ_MAPPING ((STANDARD_RIGHTS_READ) | \
  821. (ACTRL_DS_LIST) | \
  822. (ACTRL_DS_READ_PROP) | \
  823. (ACTRL_DS_LIST_OBJECT))
  824. // generic execute
  825. #define LSAP_DS_GENERIC_EXECUTE_MAPPING ((STANDARD_RIGHTS_EXECUTE) | \
  826. (ACTRL_DS_LIST_OBJECT))
  827. // generic right
  828. #define LSAP_DS_GENERIC_WRITE_MAPPING ((STANDARD_RIGHTS_WRITE) | \
  829. (ACTRL_DS_SELF) | \
  830. (ACTRL_DS_WRITE_PROP))
  831. // generic all
  832. #define LSAP_DS_GENERIC_ALL_MAPPING ((STANDARD_RIGHTS_REQUIRED) | \
  833. (ACTRL_DS_CREATE_CHILD) | \
  834. (ACTRL_DS_DELETE_CHILD) | \
  835. (ACTRL_DS_DELETE_TREE) | \
  836. (ACTRL_DS_READ_PROP) | \
  837. (ACTRL_DS_WRITE_PROP) | \
  838. (ACTRL_DS_LIST) | \
  839. (ACTRL_DS_LIST_OBJECT) | \
  840. (ACTRL_DS_CONTROL_ACCESS) | \
  841. (ACTRL_DS_SELF))
  842. //
  843. // Standard DS generic access rights mapping
  844. //
  845. #define LSAP_DS_GENERIC_MAPPING { \
  846. LSAP_DS_GENERIC_READ_MAPPING, \
  847. LSAP_DS_GENERIC_WRITE_MAPPING, \
  848. LSAP_DS_GENERIC_EXECUTE_MAPPING, \
  849. LSAP_DS_GENERIC_ALL_MAPPING}
  850. NTSTATUS
  851. LsapDbRequestAccessObject(
  852. IN OUT LSAPR_HANDLE ObjectHandle,
  853. IN PLSAP_DB_OBJECT_INFORMATION ObjectInformation,
  854. IN ACCESS_MASK DesiredAccess,
  855. IN ULONG Options
  856. )
  857. /*++
  858. Routine Description:
  859. This function performs an access check for an LSA Database object. While
  860. impersonating an RPC client, the specified Desired Accesses are reconciled
  861. with the Discretionary Access Control List (DACL) in the object's
  862. Security Descriptor. Note that the object's Security Descriptor is
  863. passed explicitly so that this routine can be called for new objects
  864. for which a SD has been constructed but not yet written to the
  865. Registry.
  866. Arguments:
  867. ObjectHandle - Handle to object. The handle will receive the
  868. granted accesses if the call is successful.
  869. ObjectInformation - Pointer to object's information. As a minimum, the
  870. object's Security Descriptor must be set up.
  871. DesiredAccess - Specifies a mask of the access types desired to the
  872. object.
  873. Options - Specifies optional actions to be taken
  874. Return Value:
  875. NTSTATUS - Standard Nt Result Code
  876. STATUS_ACCESS_DENIED - Not all of the Desired Accessed can be
  877. granted to the caller.
  878. STATUS_BACKUP_CONTROLLER - A create, update or delete operation
  879. is not allowed for a non-trusted client for this object on a BDC,
  880. because the object is global to all DC's for a domain and is replicated.
  881. Errors from RPC client impersonation
  882. --*/
  883. {
  884. NTSTATUS Status = STATUS_SUCCESS, RevertStatus = STATUS_SUCCESS, AccessStatus = STATUS_SUCCESS;
  885. LSAP_DB_HANDLE InternalHandle = (LSAP_DB_HANDLE) ObjectHandle;
  886. LSAP_DB_OBJECT_TYPE_ID ObjectTypeId = InternalHandle->ObjectTypeId;
  887. LSAP_DB_OBJECT_TYPE_ID ObjectTypeIdForGenericMapping;
  888. ULONG EffectiveOptions = Options | InternalHandle->Options;
  889. GENERIC_MAPPING LsapDsGenericMap = LSAP_DS_GENERIC_MAPPING;
  890. #ifdef LSAP_TRACK_HANDLE
  891. HANDLE ClientToken = NULL;
  892. #endif
  893. ULONG TrustedDomainTypeCount = 0;
  894. ULONG GlobalSecretTypeCount = sizeof( GlobalSecretTypeList ) / sizeof( OBJECT_TYPE_LIST );
  895. ULONG GrantedAccess = 0;
  896. POBJECT_TYPE_LIST TypeListToCheck = NULL;
  897. LSAP_DS_OBJECT_ACCESS_MAP * MappingTableToUse = NULL;
  898. ULONG TypeListToCheckCount = 0;
  899. ULONG MappingTableSize=0;
  900. ULONG AccessStatusArray[ TDTYPE_LIST_SIZE ];
  901. ULONG GrantedAccessArray[ TDTYPE_LIST_SIZE ];
  902. BOOLEAN fAtLeastOneAccessGranted = FALSE;
  903. BOOLEAN fNoAccessRequested = FALSE;
  904. BOOLEAN IsAnonymous = FALSE;
  905. BOOLEAN MustLogAnonymousAccessDenied = FALSE;
  906. //
  907. // AccessStatusArray and GrantedAccessArray are set to the larger of the
  908. // two counts: TDTYPE_LIST_SIZE and SECRETTYPE_LIST_SIZE
  909. //
  910. ASSERT( TDTYPE_LIST_SIZE > SECRETTYPE_LIST_SIZE );
  911. // This routine should not be called on trusted clients
  912. ASSERT( !InternalHandle->Trusted );
  913. //
  914. // Get the correct object type id for generic mapping
  915. //
  916. if ( FLAG_ON( InternalHandle->Options, LSAP_DB_DS_TRUSTED_DOMAIN_AS_SECRET ) )
  917. {
  918. ObjectTypeIdForGenericMapping = SecretObject;
  919. }
  920. else
  921. {
  922. ObjectTypeIdForGenericMapping = ObjectTypeId;
  923. }
  924. //
  925. // Map any Generic Access Types to Specific Access Types
  926. //
  927. RtlMapGenericMask(
  928. &DesiredAccess,
  929. &(LsapDbState.DbObjectTypes[ObjectTypeIdForGenericMapping].GenericMapping)
  930. );
  931. //
  932. // Common path for Object Open and Creation. We need to reconcile
  933. // the desired accesses to the object with the Discretionary Access
  934. // Control List contained in the Security Descriptor. Note that this
  935. // needs to be done even for newly created objects, since they are
  936. // being opened as well as created.
  937. //
  938. // Impersonate the client thread prior to doing an access check.
  939. //
  940. if ( Options & LSAP_DB_USE_LPC_IMPERSONATE ) {
  941. Status = LsapImpersonateClient( );
  942. } else {
  943. Status = I_RpcMapWin32Status(RpcImpersonateClient(0));
  944. }
  945. if (!NT_SUCCESS(Status)) {
  946. return Status;
  947. }
  948. //
  949. // Reconcile the desired access with the discretionary ACL
  950. // of the Resultant Descriptor. Note that this operation is performed
  951. // even if we are just creating the object since the object is to
  952. // be opened.
  953. //
  954. switch ( InternalHandle->ObjectTypeId ) {
  955. case TrustedDomainObject:
  956. if ( !LsaDsStateInfo.UseDs ) {
  957. break;
  958. }
  959. if ( FLAG_ON( InternalHandle->Options, LSAP_DB_DS_TRUSTED_DOMAIN_AS_SECRET ) )
  960. {
  961. MappingTableToUse = TrustedDomainAsSecretAccessMap;
  962. MappingTableSize = TrustedDomainAsSecretAccessMapSize;
  963. }
  964. else
  965. {
  966. MappingTableToUse = TrustedDomainAccessMap;
  967. MappingTableSize = TrustedDomainAccessMapSize;
  968. }
  969. TypeListToCheck = TrustedDomainTypeList;
  970. TypeListToCheckCount = TDTYPE_LIST_SIZE ;
  971. break;
  972. case SecretObject:
  973. //
  974. // Bug #340164: anonymous users are not allowed to look at secrets
  975. //
  976. if ( LsapGlobalRestrictAnonymous &&
  977. (( LSAP_DB_HANDLE )ObjectInformation->ObjectAttributes.RootDirectory)->Options & LSAP_DB_OPENED_BY_ANONYMOUS ) {
  978. Status = STATUS_ACCESS_DENIED;
  979. break;
  980. }
  981. //
  982. // If we are running on a client, don't specify a property list, or it'll fail
  983. //
  984. if ( !LsaDsStateInfo.UseDs ) {
  985. break;
  986. }
  987. if ( FLAG_ON( InternalHandle->Options, LSAP_DB_DS_TRUSTED_DOMAIN_AS_SECRET ) ) {
  988. TypeListToCheck = TrustedDomainTypeList;
  989. TypeListToCheckCount = TDTYPE_LIST_SIZE;
  990. MappingTableToUse = TrustedDomainAsSecretAccessMap;
  991. MappingTableSize = TrustedDomainAsSecretAccessMapSize;
  992. } else if ( FLAG_ON( InternalHandle->Options, LSAP_DB_OBJECT_SCOPE_DS ) ) {
  993. TypeListToCheck = GlobalSecretTypeList;
  994. TypeListToCheckCount = SECRETTYPE_LIST_SIZE;
  995. MappingTableToUse = GlobalSecretAccessMap;
  996. MappingTableSize = GlobalSecretAccessMapSize;
  997. }
  998. break;
  999. case AccountObject:
  1000. //
  1001. // Bug #340164: anonymous users are not allowed to look at accounts
  1002. //
  1003. if ( LsapGlobalRestrictAnonymous &&
  1004. (( LSAP_DB_HANDLE )ObjectInformation->ObjectAttributes.RootDirectory)->Options & LSAP_DB_OPENED_BY_ANONYMOUS ) {
  1005. Status = STATUS_ACCESS_DENIED;
  1006. break;
  1007. }
  1008. case PolicyObject:
  1009. {
  1010. HANDLE ClientToken;
  1011. //
  1012. // Determine if the caller is anonymous
  1013. //
  1014. Status = NtOpenThreadToken( NtCurrentThread(),
  1015. TOKEN_QUERY,
  1016. FALSE,
  1017. &ClientToken );
  1018. if ( NT_SUCCESS( Status ) ) {
  1019. UCHAR Buffer[ 128 ];
  1020. PTOKEN_USER User ;
  1021. ULONG Size ;
  1022. User = (PTOKEN_USER) Buffer ;
  1023. Status = NtQueryInformationToken(
  1024. ClientToken,
  1025. TokenUser,
  1026. User,
  1027. sizeof( Buffer ),
  1028. &Size );
  1029. if ( NT_SUCCESS( Status ) ) {
  1030. if ( LsapGlobalRestrictAnonymous &&
  1031. RtlEqualSid( User->User.Sid, LsapAnonymousSid ) ) {
  1032. if ( LsapProductType == NtProductLanManNt ) {
  1033. //
  1034. // Bug #340164: on DCs, mark handles opened by
  1035. // anonymous users as such
  1036. //
  1037. IsAnonymous = TRUE;
  1038. InternalHandle->Options |= LSAP_DB_OPENED_BY_ANONYMOUS;
  1039. } else {
  1040. //
  1041. // Bug #340164: on non-DCs, prevent anonymous
  1042. // users from opening LSA policy handles
  1043. //
  1044. static LONGLONG LsapAnonymousRejectedLastLogged = 0;
  1045. LONGLONG CurrentTime;
  1046. Status = STATUS_ACCESS_DENIED;
  1047. GetSystemTimeAsFileTime(( PFILETIME )&CurrentTime );
  1048. if (( CurrentTime - LsapAnonymousRejectedLastLogged ) >= ( 24i64 * 60 * 60 * 10 * 1000 * 1000 )) {
  1049. LsapAnonymousRejectedLastLogged = CurrentTime;
  1050. MustLogAnonymousAccessDenied = TRUE;
  1051. }
  1052. }
  1053. }
  1054. }
  1055. NtClose( ClientToken );
  1056. }
  1057. }
  1058. default:
  1059. break;
  1060. }
  1061. if( NT_SUCCESS( Status ) ) {
  1062. if( NULL != MappingTableToUse ) {
  1063. Status = NtAccessCheckByTypeResultListAndAuditAlarm(
  1064. &LsapState.SubsystemName,
  1065. ObjectHandle,
  1066. &LsapDbObjectTypeNames[ObjectTypeId],
  1067. ( PUNICODE_STRING )ObjectInformation->ObjectAttributes.ObjectName,
  1068. ObjectInformation->ObjectAttributes.SecurityDescriptor,
  1069. NULL, // Principal Self sid
  1070. MAXIMUM_ALLOWED |
  1071. ((DesiredAccess & ACCESS_SYSTEM_SECURITY )?
  1072. ACCESS_SYSTEM_SECURITY:0),
  1073. AuditEventObjectAccess,
  1074. 0, // FLAGS
  1075. TypeListToCheck,
  1076. TypeListToCheckCount,
  1077. &LsapDsGenericMap,
  1078. FALSE,
  1079. GrantedAccessArray,
  1080. AccessStatusArray,
  1081. ( PBOOLEAN )&( InternalHandle->GenerateOnClose ) );
  1082. } else {
  1083. //
  1084. // In Policy object case there are two rights, that must be defered to provide compatibility
  1085. // with previous versions; POLICY_TRUST_ADMIN, READ_CONTROL. Why these have to be defered
  1086. // is explained below;
  1087. //
  1088. //
  1089. // Don't fail the LsaOpenPolicy just because POLICY_TRUST_ADMIN access is requested
  1090. //
  1091. // NT 4.0 and older required that the caller ask for POLICY_TRUST_ADMIN to manipulate TDOs.
  1092. // That's no longer required, but some applications still ask for it. So, don't fail
  1093. // the LsaOpenPolicy if the access isn't granted. Rather, let the individual call fail
  1094. // when it checks to see if the access was granted on the handle.
  1095. //
  1096. // TDOs access is now controlled by the security descriptor on the TDO. That allows
  1097. // delegation of TDO manipulation.
  1098. //
  1099. //
  1100. // Don't fail the LsaOpenPolicy just because the anonymous user asked for
  1101. // READ_CONTROL. Some apps ask for GENERIC_EXECUTE which contains READ_CONTROL
  1102. // even though the app really doesn't need it.
  1103. //
  1104. ULONG RequestedAccess = DesiredAccess;
  1105. ULONG DeferAccess[] = {
  1106. 0,
  1107. POLICY_TRUST_ADMIN,
  1108. READ_CONTROL,
  1109. POLICY_TRUST_ADMIN | READ_CONTROL
  1110. };
  1111. ULONG i;
  1112. ULONG NumberOfIterations = ( ObjectTypeId == PolicyObject ? RTL_NUMBER_OF( DeferAccess ) : 1 );
  1113. for( i = 0; i < NumberOfIterations; ++i ) {
  1114. if( ObjectTypeId == PolicyObject ) {
  1115. //
  1116. // If the access to be defered is not asked for
  1117. // then just skip this.
  1118. //
  1119. if( ( RequestedAccess & DeferAccess[i] ) != DeferAccess[i] ) {
  1120. continue;
  1121. }
  1122. //
  1123. // If the access to be defered contains READ_CONTROL, and
  1124. // the user is not anonymous then skip it since READ_CONTROL
  1125. // must be defered only anonymous case
  1126. //
  1127. if( FLAG_ON( DeferAccess[i], READ_CONTROL ) &&
  1128. !IsAnonymous ) {
  1129. continue;
  1130. }
  1131. DesiredAccess = RequestedAccess & ~DeferAccess[i];
  1132. }
  1133. //
  1134. // Because of bug 411289, the NtAccessCheck* API's don't return
  1135. // ACCESS_DENIED when presented with 0 access. Because clients
  1136. // may already expect this behavoir, only return ACCESS_DENIED
  1137. // when the client really doesn't have any access. We want to
  1138. // return ACCESS_DENIED to prevent anonymous clients from acquiring
  1139. // handles.
  1140. //
  1141. if ( DesiredAccess == 0 ) {
  1142. fNoAccessRequested = TRUE;
  1143. DesiredAccess = MAXIMUM_ALLOWED;
  1144. }
  1145. Status = NtAccessCheckByTypeAndAuditAlarm(
  1146. &LsapState.SubsystemName,
  1147. ObjectHandle,
  1148. &LsapDbObjectTypeNames[ObjectTypeId],
  1149. ( PUNICODE_STRING )ObjectInformation->ObjectAttributes.ObjectName,
  1150. ObjectInformation->ObjectAttributes.SecurityDescriptor,
  1151. NULL, // Principal Self sid
  1152. DesiredAccess,
  1153. AuditEventObjectAccess,
  1154. 0, // FLAGS
  1155. TypeListToCheck,
  1156. TypeListToCheckCount,
  1157. &( LsapDbState.DbObjectTypes[ ObjectTypeId ].GenericMapping ),
  1158. FALSE,
  1159. ( PACCESS_MASK )&GrantedAccess ,
  1160. ( PNTSTATUS )&AccessStatus,
  1161. ( PBOOLEAN )&( InternalHandle->GenerateOnClose ) );
  1162. if ( fNoAccessRequested ) {
  1163. DesiredAccess = 0;
  1164. if ( NT_SUCCESS( Status )
  1165. && NT_SUCCESS( AccessStatus ) ) {
  1166. GrantedAccess = 0;
  1167. }
  1168. }
  1169. if( !NT_SUCCESS( Status ) ||
  1170. AccessStatus != STATUS_ACCESS_DENIED ) {
  1171. break;
  1172. }
  1173. }
  1174. }
  1175. }
  1176. if ( NT_SUCCESS( Status ) ){
  1177. ULONG i,j;
  1178. switch ( InternalHandle->ObjectTypeId ) {
  1179. case SecretObject:
  1180. case TrustedDomainObject:
  1181. //
  1182. // If we are running on a client, or local secret No need to do any mapping
  1183. //
  1184. if (NULL==MappingTableToUse) {
  1185. break;
  1186. }
  1187. //
  1188. // Take standard rights from the object guid level in the type list
  1189. //
  1190. GrantedAccess = 0;
  1191. if (NT_SUCCESS(AccessStatusArray[0]))
  1192. {
  1193. GrantedAccess |= (GrantedAccessArray[0]) & ((STANDARD_RIGHTS_ALL)|ACCESS_SYSTEM_SECURITY);
  1194. }
  1195. for (i=0;i<TypeListToCheckCount;i++)
  1196. {
  1197. if (NT_SUCCESS(AccessStatusArray[i]))
  1198. {
  1199. fAtLeastOneAccessGranted = TRUE;
  1200. for (j=0;j<MappingTableSize;j++)
  1201. {
  1202. if ((0==memcmp(MappingTableToUse[j].ObjectGuid,TypeListToCheck[i].ObjectType,sizeof(GUID)))
  1203. && (GrantedAccessArray[i] & MappingTableToUse[j].DsAccessRequired))
  1204. {
  1205. //
  1206. // Or in the downlevel right granted by virtue of the granted DS right
  1207. // on the particular prop set guid
  1208. //
  1209. GrantedAccess |= MappingTableToUse[j].DesiredAccess;
  1210. }
  1211. }
  1212. }
  1213. }
  1214. //
  1215. // Grant in the unused trusted domain access bits
  1216. //
  1217. if (TrustedDomainObject == InternalHandle->ObjectTypeId)
  1218. {
  1219. GrantedAccess |=TRUSTED_QUERY_CONTROLLERS|TRUSTED_SET_CONTROLLERS;
  1220. }
  1221. if ( !fAtLeastOneAccessGranted )
  1222. {
  1223. // No access' granted
  1224. GrantedAccess = 0;
  1225. AccessStatus = STATUS_ACCESS_DENIED;
  1226. }
  1227. else if (DesiredAccess & MAXIMUM_ALLOWED)
  1228. {
  1229. //
  1230. // Granted access already contains the maximum allowed access in lsa terms as
  1231. // computed above
  1232. //
  1233. AccessStatus = STATUS_SUCCESS;
  1234. }
  1235. else if (RtlAreAllAccessesGranted(GrantedAccess,DesiredAccess))
  1236. {
  1237. GrantedAccess = DesiredAccess;
  1238. AccessStatus = STATUS_SUCCESS;
  1239. }
  1240. else
  1241. {
  1242. //
  1243. // One or more accesses that were requested was not granted
  1244. //
  1245. GrantedAccess = 0;
  1246. AccessStatus = STATUS_ACCESS_DENIED;
  1247. }
  1248. break;
  1249. default:
  1250. break;
  1251. }
  1252. if (NT_SUCCESS(AccessStatus))
  1253. {
  1254. InternalHandle->GrantedAccess = GrantedAccess;
  1255. }
  1256. }
  1257. //
  1258. // Check to see whether this is a network request that is coming in or
  1259. // not
  1260. //
  1261. if ( NT_SUCCESS( Status ) && NT_SUCCESS( AccessStatus ) &&
  1262. InternalHandle->ObjectTypeId == SecretObject ) {
  1263. Status = LsapDbIsRpcClientNetworkClient( &InternalHandle->NetworkClient );
  1264. }
  1265. #ifdef LSAP_TRACK_HANDLE
  1266. //
  1267. // If we haven't already done so, open the client token so we can copy it off below
  1268. //
  1269. if ( !InternalHandle->ClientToken ) {
  1270. Status = NtOpenThreadToken( NtCurrentThread(),
  1271. TOKEN_QUERY | TOKEN_DUPLICATE,
  1272. TRUE,
  1273. &ClientToken );
  1274. }
  1275. #endif
  1276. //
  1277. // Before checking the Status, stop impersonating the client and become
  1278. // our former self.
  1279. //
  1280. if ( Options & LSAP_DB_USE_LPC_IMPERSONATE ) {
  1281. RevertToSelf();
  1282. RevertStatus = STATUS_SUCCESS;
  1283. } else {
  1284. RevertStatus = I_RpcMapWin32Status(RpcRevertToSelf());
  1285. if (!NT_SUCCESS(RevertStatus)) {
  1286. LsapLogError(
  1287. "LsapDbRequestAccessObject: RpcRevertToSelf failed 0x%lx\n",
  1288. RevertStatus
  1289. );
  1290. }
  1291. }
  1292. #ifdef LSAP_TRACK_HANDLE
  1293. //
  1294. // Copy off the client token
  1295. //
  1296. if ( ClientToken ) {
  1297. OBJECT_ATTRIBUTES ObjAttrs;
  1298. SECURITY_QUALITY_OF_SERVICE SecurityQofS;
  1299. //
  1300. // Duplicate the token
  1301. //
  1302. InitializeObjectAttributes( &ObjAttrs, NULL, 0L, NULL, NULL );
  1303. SecurityQofS.Length = sizeof( SECURITY_QUALITY_OF_SERVICE );
  1304. SecurityQofS.ImpersonationLevel = SecurityImpersonation;
  1305. SecurityQofS.ContextTrackingMode = FALSE; // Snapshot client context
  1306. SecurityQofS.EffectiveOnly = FALSE;
  1307. ObjAttrs.SecurityQualityOfService = &SecurityQofS;
  1308. Status = NtDuplicateToken( ClientToken,
  1309. TOKEN_READ | TOKEN_WRITE | TOKEN_EXECUTE,
  1310. &ObjAttrs,
  1311. FALSE,
  1312. TokenImpersonation,
  1313. &InternalHandle->ClientToken );
  1314. NtClose( ClientToken );
  1315. }
  1316. #endif
  1317. if ( MustLogAnonymousAccessDenied ) {
  1318. //
  1319. // REVIEW: replace the foregoing by a call to LsapGetClientNetworkAddress
  1320. //
  1321. RPC_STATUS Local;
  1322. UNICODE_STRING Name = {0};
  1323. RPC_BINDING_HANDLE ServerBinding = NULL;
  1324. Local = RpcBindingServerFromClient(
  1325. NULL, // in context of an RPC call, client binding not required
  1326. &ServerBinding
  1327. );
  1328. if ( Local == RPC_S_OK ) {
  1329. WCHAR * StringBinding = NULL;
  1330. Local = RpcBindingToStringBindingW(
  1331. ServerBinding,
  1332. &StringBinding
  1333. );
  1334. if ( Local == RPC_S_OK ) {
  1335. Local = RpcStringBindingParseW(
  1336. StringBinding,
  1337. NULL, // don't care about UUID
  1338. NULL, // don't care about ProtSeq
  1339. &Name.Buffer,
  1340. NULL, // don't care about EndPoint
  1341. NULL // don't care about NetworkOptions
  1342. );
  1343. if ( Local == RPC_S_OK ) {
  1344. Name.Length = wcslen( Name.Buffer ) * sizeof( WCHAR );
  1345. Name.MaximumLength = Name.Length + sizeof( WCHAR );
  1346. }
  1347. }
  1348. if ( StringBinding != NULL ) {
  1349. RpcStringFreeW( &StringBinding );
  1350. }
  1351. }
  1352. SpmpReportEventU(
  1353. EVENTLOG_ERROR_TYPE,
  1354. LSA_OPEN_POLICY_BY_ANONYMOUS_REJECTED,
  1355. 0,
  1356. 0,
  1357. NULL,
  1358. 1,
  1359. &Name
  1360. );
  1361. if ( Name.Buffer != NULL ) {
  1362. RpcStringFreeW( &Name.Buffer );
  1363. }
  1364. if ( ServerBinding != NULL ) {
  1365. RpcBindingFree( ServerBinding );
  1366. }
  1367. }
  1368. //
  1369. // If the primary status code is a success status code, return the
  1370. // secondary status code. If this is alsoa success code, return the
  1371. // revert to self status.
  1372. //
  1373. if (NT_SUCCESS(Status)) {
  1374. Status = AccessStatus;
  1375. if (NT_SUCCESS(Status)) {
  1376. Status = RevertStatus;
  1377. }
  1378. }
  1379. return Status;
  1380. }
  1381. NTSTATUS
  1382. LsapDbRequestAccessNewObject(
  1383. IN OUT LSAPR_HANDLE ObjectHandle,
  1384. IN PLSAP_DB_OBJECT_INFORMATION ObjectInformation,
  1385. IN ACCESS_MASK DesiredAccess,
  1386. IN ULONG Options
  1387. )
  1388. /*++
  1389. Routine Description:
  1390. This function verifies that a desired set of accesses can be granted
  1391. to the handle that is opened when a new object is created.
  1392. It is important to note that the rules for granting accesses to the
  1393. handle that is open upon object creation are different from the rules
  1394. for granting accesses upon the opening of an existing object. For a new
  1395. object, the associated handle will be granted any subset of GENERIC_ALL
  1396. access desired and, if the creator has SE_SECURITY_PRIVILEGE, the handle
  1397. will be granted ACCESS_SYSTEM_SECURITY access if requested. If the
  1398. creator requests MAXIMUM_ALLOWED, the handle will be granted GENERIC_ALL.
  1399. Arguments:
  1400. ObjectHandle - Handle to object. The handle will receive the
  1401. granted accesses if the call is successful.
  1402. ObjectInformation - Pointer to object's information. As a minimum, the
  1403. object's Security Descriptor must be set up.
  1404. DesiredAccess - Specifies a mask of the access types desired to the
  1405. object.
  1406. Options - Specifies optional actions to be taken
  1407. Return Value:
  1408. NTSTATUS - Standard Nt Result Code
  1409. STATUS_ACCESS_DENIED - Not all of the Desired Accessed can be
  1410. granted to the caller.
  1411. STATUS_BACKUP_CONTROLLER - A create, update or delete operation
  1412. is not allowed for a non-trusted client for this object on a BDC,
  1413. because the object is global to all DC's for a domain and is replicated.
  1414. --*/
  1415. {
  1416. NTSTATUS Status = STATUS_SUCCESS;
  1417. ACCESS_MASK EffectiveDesiredAccess = DesiredAccess;
  1418. LSAP_DB_HANDLE InternalHandle = (LSAP_DB_HANDLE) ObjectHandle;
  1419. LSAP_DB_OBJECT_TYPE_ID ObjectTypeId = InternalHandle->ObjectTypeId;
  1420. ULONG EffectiveOptions = Options | InternalHandle->Options;
  1421. #ifndef LSADS_MAP_SD
  1422. if ( LsapDsIsWriteDs( ObjectHandle ) ) {
  1423. LsapDsDebugOut(( DEB_TRACE, "Shortcurcuit Ds access check\n" ));
  1424. InternalHandle->GrantedAccess = 0xFFFFFFFF;
  1425. return( STATUS_SUCCESS );
  1426. }
  1427. #endif
  1428. //
  1429. // If MAXIMUM_ALLOWED is requested, add GENERIC_ALL
  1430. //
  1431. if (EffectiveDesiredAccess & MAXIMUM_ALLOWED) {
  1432. EffectiveDesiredAccess |= GENERIC_ALL;
  1433. }
  1434. //
  1435. // If ACCESS_SYSTEM_SECURITY is requested and we are a non-trusted
  1436. // client, check that we have SE_SECURITY_PRIVILEGE.
  1437. //
  1438. if ((EffectiveDesiredAccess & ACCESS_SYSTEM_SECURITY) &&
  1439. (!InternalHandle->Trusted)) {
  1440. Status = LsapRtlWellKnownPrivilegeCheck(
  1441. (PVOID)ObjectHandle,
  1442. SE_SECURITY_PRIVILEGE
  1443. );
  1444. if (!NT_SUCCESS(Status)) {
  1445. goto RequestAccessNewObjectError;
  1446. }
  1447. }
  1448. //
  1449. // Make sure the caller can be given the requested access
  1450. // to the new object
  1451. //
  1452. InternalHandle->GrantedAccess = EffectiveDesiredAccess;
  1453. RtlMapGenericMask(
  1454. &InternalHandle->GrantedAccess,
  1455. &LsapDbState.DbObjectTypes[ObjectTypeId].GenericMapping
  1456. );
  1457. if ((LsapDbState.DbObjectTypes[ObjectTypeId].InvalidMappedAccess
  1458. &InternalHandle->GrantedAccess) != 0) {
  1459. Status = STATUS_ACCESS_DENIED;
  1460. goto RequestAccessNewObjectError;
  1461. }
  1462. RequestAccessNewObjectFinish:
  1463. return(Status);
  1464. RequestAccessNewObjectError:
  1465. goto RequestAccessNewObjectFinish;
  1466. }
  1467. NTSTATUS
  1468. LsapDbCloseObject (
  1469. IN PLSAPR_HANDLE ObjectHandle,
  1470. IN ULONG Options,
  1471. IN NTSTATUS PreliminaryStatus
  1472. )
  1473. /*++
  1474. Routine Description:
  1475. This function closes (dereferences) a handle to an Lsa Database object.
  1476. If the reference count of the handle reduces to 0, the handle is freed.
  1477. Arguments:
  1478. ObjectHandle - Pointer to handle to object from LsapDbOpenObject or
  1479. LsapDbCreateObject.
  1480. Options - Optional actions to be performed
  1481. LSAP_DB_VALIDATE_HANDLE - Verify that the handle is valid.
  1482. LSAP_DB_DEREFERENCE_CONTR - Dereference the Container Handle. Note
  1483. that the Container Handle was referenced when the subordinate
  1484. handle was created.
  1485. LSAP_DB_ADMIT_DELETED_OBJECT_HANDLES - Permit the handle provided
  1486. to be for a deleted object.
  1487. PreliminaryStatus - Used to decide whether to abort or commit the transaction
  1488. Return Value:
  1489. NTSTATUS - Standard Nt Result Code
  1490. --*/
  1491. {
  1492. NTSTATUS Status;
  1493. //
  1494. // Dereference the object handle and free the handle if the reference count
  1495. // reaches zero. Optionally, the handle will be verified and/or freed
  1496. // and the container object handle dereferenced.
  1497. //
  1498. Status = LsapDbDereferenceObject(
  1499. ObjectHandle,
  1500. NullObject,
  1501. NullObject,
  1502. Options,
  1503. (SECURITY_DB_DELTA_TYPE) 0,
  1504. PreliminaryStatus
  1505. );
  1506. *ObjectHandle = NULL;
  1507. return(Status);
  1508. }
  1509. NTSTATUS
  1510. LsapDbDeleteObject(
  1511. IN LSAPR_HANDLE ObjectHandle
  1512. )
  1513. /*++
  1514. Routine Description:
  1515. This function deletes an object from the Lsa Database.
  1516. Arguments:
  1517. ObjectHandle - Handle to open object to be deleted.
  1518. Return Value:
  1519. NTSTATUS - Standard NT Result Code.
  1520. STATUS_INVALID_HANDLE - Handle is not a valid handle to an open
  1521. object.
  1522. STATUS_ACCESS_DENIED - Handle does not specify DELETE access.
  1523. --*/
  1524. {
  1525. NTSTATUS Status;
  1526. LSAP_DB_HANDLE Handle = (LSAP_DB_HANDLE) ObjectHandle;
  1527. PUNICODE_STRING AttributeNames[LSAP_DB_MAX_ATTRIBUTES];
  1528. BOOLEAN DeleteSecurely[LSAP_DB_MAX_ATTRIBUTES] = {0};
  1529. PUNICODE_STRING *NextAttributeName;
  1530. LSAP_DB_ATTRIBUTE Attributes[ 2 ];
  1531. ULONG AttributeCount;
  1532. ULONG AttributeNumber;
  1533. LSAPR_TRUST_INFORMATION TrustInformation;
  1534. BOOLEAN TrustedDomainCacheIsUpToDate = TRUE;
  1535. //
  1536. // All object types have a Security Descriptor stored as the SecDesc
  1537. // attribute.
  1538. //
  1539. NextAttributeName = AttributeNames;
  1540. AttributeCount = 0;
  1541. *NextAttributeName = &LsapDbNames[SecDesc];
  1542. NextAttributeName++;
  1543. AttributeCount++;
  1544. Status = STATUS_SUCCESS;
  1545. //
  1546. // Check the other references to the object and mark all other handles
  1547. // invalid.
  1548. //
  1549. Status = LsapDbMarkDeletedObjectHandles( ObjectHandle, FALSE );
  1550. if (!NT_SUCCESS(Status)) {
  1551. goto DeleteObjectError;
  1552. }
  1553. //
  1554. // Switch on object type
  1555. //
  1556. switch (Handle->ObjectTypeId) {
  1557. case PolicyObject:
  1558. Status = STATUS_INVALID_PARAMETER;
  1559. break;
  1560. case TrustedDomainObject:
  1561. //
  1562. // Deal with the TrustedDomainAsSecret problem
  1563. if (FLAG_ON( Handle->Options, LSAP_DB_DS_TRUSTED_DOMAIN_AS_SECRET ) ) {
  1564. LsapDbInitializeAttributeDs( &Attributes[ 0 ],
  1565. TrDmSAI,
  1566. NULL,
  1567. 0,
  1568. FALSE );
  1569. LsapDbInitializeAttributeDs( &Attributes[ 1 ],
  1570. TrDmSAO,
  1571. NULL,
  1572. 0,
  1573. FALSE );
  1574. } else {
  1575. //
  1576. // Check for delegatable trust deletion quotas
  1577. //
  1578. if ( LsapDsIsHandleDsHandle( ObjectHandle )) {
  1579. Status = LsapCheckTDODeletionQuotas(ObjectHandle);
  1580. } else {
  1581. Status = STATUS_SUCCESS;
  1582. }
  1583. if (NT_SUCCESS(Status)) {
  1584. *NextAttributeName = &LsapDbNames[TrDmName];
  1585. NextAttributeName++;
  1586. AttributeCount++;
  1587. *NextAttributeName = &LsapDbNames[Sid];
  1588. NextAttributeName++;
  1589. AttributeCount++;
  1590. *NextAttributeName = &LsapDbNames[TrDmAcN];
  1591. NextAttributeName++;
  1592. AttributeCount++;
  1593. *NextAttributeName = &LsapDbNames[TrDmCtN];
  1594. NextAttributeName++;
  1595. AttributeCount++;
  1596. *NextAttributeName = &LsapDbNames[TrDmPxOf];
  1597. NextAttributeName++;
  1598. AttributeCount++;
  1599. *NextAttributeName = &LsapDbNames[TrDmCtEn];
  1600. NextAttributeName++;
  1601. AttributeCount++;
  1602. //
  1603. // Delete the object from the list of Trusted Domains
  1604. //
  1605. TrustInformation.Sid = Handle->Sid;
  1606. TrustInformation.Name = *((PLSAPR_UNICODE_STRING) &Handle->LogicalNameU);
  1607. Status = LsapDbAcquireWriteLockTrustedDomainList();
  1608. if ( NT_SUCCESS( Status )) {
  1609. Status = LsapDbDeleteTrustedDomainList( &TrustInformation );
  1610. TrustedDomainCacheIsUpToDate = FALSE;
  1611. LsapDbReleaseLockTrustedDomainList();
  1612. }
  1613. //
  1614. // Then, delete the sam account corresponding to this trust, if it existed
  1615. //
  1616. Status = LsapDsDeleteInterdomainTrustAccount( ObjectHandle );
  1617. }
  1618. }
  1619. break;
  1620. case AccountObject:
  1621. *NextAttributeName = &LsapDbNames[Sid];
  1622. NextAttributeName++;
  1623. AttributeCount++;
  1624. *NextAttributeName = &LsapDbNames[ActSysAc];
  1625. NextAttributeName++;
  1626. AttributeCount++;
  1627. *NextAttributeName = &LsapDbNames[Privilgs];
  1628. NextAttributeName++;
  1629. AttributeCount++;
  1630. //
  1631. // BUG 667716: QuotaLim appears to be dead code, but it is not.
  1632. // Accounts on machines upgraded from NT4 may have this
  1633. // value set on them, in which case they will not be
  1634. // deleted properly unless QuotaLim is deleted also,
  1635. // leading to LSA account database corruption and
  1636. // inability to enumerate accounts and replicate to DCs
  1637. //
  1638. *NextAttributeName = &LsapDbNames[QuotaLim];
  1639. NextAttributeName++;
  1640. AttributeCount++;
  1641. break;
  1642. case SecretObject:
  1643. DeleteSecurely[AttributeCount] = TRUE;
  1644. *NextAttributeName = &LsapDbNames[CurrVal];
  1645. NextAttributeName++;
  1646. AttributeCount++;
  1647. DeleteSecurely[AttributeCount] = TRUE;
  1648. *NextAttributeName = &LsapDbNames[OldVal];
  1649. NextAttributeName++;
  1650. AttributeCount++;
  1651. *NextAttributeName = &LsapDbNames[CupdTime];
  1652. NextAttributeName++;
  1653. AttributeCount++;
  1654. *NextAttributeName = &LsapDbNames[OupdTime];
  1655. NextAttributeName++;
  1656. AttributeCount++;
  1657. break;
  1658. default:
  1659. Status = STATUS_INVALID_PARAMETER;
  1660. break;
  1661. }
  1662. if (!NT_SUCCESS(Status)) {
  1663. goto DeleteObjectError;
  1664. }
  1665. //
  1666. // Add Registry Transactions to delete each of the object's attributes.
  1667. //
  1668. for(AttributeNumber = 0;
  1669. AttributeNumber < AttributeCount && !LsapDsIsHandleDsHandle( ObjectHandle);
  1670. AttributeNumber++) {
  1671. Status = LsapDbDeleteAttributeObject(
  1672. ObjectHandle,
  1673. AttributeNames[AttributeNumber],
  1674. DeleteSecurely[AttributeNumber]
  1675. );
  1676. //
  1677. // Ignore "attribute not found" errors. The object need not
  1678. // have all attributes set, or may be only partially created.
  1679. //
  1680. if (!NT_SUCCESS(Status)) {
  1681. if (Status != STATUS_OBJECT_NAME_NOT_FOUND) {
  1682. break;
  1683. }
  1684. Status = STATUS_SUCCESS;
  1685. }
  1686. }
  1687. if (!NT_SUCCESS(Status)) {
  1688. goto DeleteObjectError;
  1689. }
  1690. //
  1691. // Close the handle to the Registry Key representing the object.
  1692. // The Registry transaction package will open another handle with
  1693. // DELETE access to perform the deletion.
  1694. //
  1695. if ( !LsapDsIsHandleDsHandle( ObjectHandle) &&
  1696. Handle->KeyHandle != NULL ) {
  1697. Status = NtClose(Handle->KeyHandle);
  1698. Handle->KeyHandle = NULL;
  1699. if (!NT_SUCCESS(Status)) {
  1700. goto DeleteObjectError;
  1701. }
  1702. }
  1703. //
  1704. // Add a Registry Transaction to delete the object's Registry Key.
  1705. //
  1706. if ( !LsapDsIsHandleDsHandle( ObjectHandle) ) {
  1707. Status = LsapRegDeleteObject( &Handle->PhysicalNameU );
  1708. } else {
  1709. //
  1710. // Deal with the special case of TrustedDomainObject as Secret
  1711. //
  1712. if ( FLAG_ON( Handle->Options, LSAP_DB_DS_TRUSTED_DOMAIN_AS_SECRET ) &&
  1713. Handle->ObjectTypeId == TrustedDomainObject) {
  1714. Status = LsapDsDeleteAttributes( &Handle->PhysicalNameDs,
  1715. Attributes,
  1716. 2 );
  1717. } else {
  1718. Status = LsapDsDeleteObject( &Handle->PhysicalNameDs );
  1719. }
  1720. }
  1721. if (!NT_SUCCESS(Status)) {
  1722. goto DeleteObjectError;
  1723. }
  1724. TrustedDomainCacheIsUpToDate = TRUE;
  1725. //
  1726. // If the machine account is being deleted, make sure to do notification on it
  1727. //
  1728. if ( Handle->ObjectTypeId == SecretObject && LsapDbSecretIsMachineAcc( Handle ) ) {
  1729. LsaINotifyChangeNotification( PolicyNotifyMachineAccountPasswordInformation );
  1730. }
  1731. DeleteObjectFinish:
  1732. if( !TrustedDomainCacheIsUpToDate ) {
  1733. if( NT_SUCCESS( LsapDbAcquireWriteLockTrustedDomainList() ) ) {
  1734. LsapDbMakeCacheInvalid( TrustedDomainObject );
  1735. LsapDbReleaseLockTrustedDomainList();
  1736. }
  1737. }
  1738. //
  1739. // Decrement the count of objects of the given type.
  1740. //
  1741. LsapDbDecrementCountObject(
  1742. ((LSAP_DB_HANDLE) ObjectHandle)->ObjectTypeId
  1743. );
  1744. return (Status);
  1745. DeleteObjectError:
  1746. goto DeleteObjectFinish;
  1747. }
  1748. NTSTATUS
  1749. LsapDbReferenceObject(
  1750. IN LSAPR_HANDLE ObjectHandle,
  1751. IN ACCESS_MASK DesiredAccess,
  1752. IN LSAP_DB_OBJECT_TYPE_ID HandleTypeId,
  1753. IN LSAP_DB_OBJECT_TYPE_ID ObjectTypeId,
  1754. IN ULONG Options
  1755. )
  1756. /*++
  1757. Routine Description:
  1758. This function verifies that a passed handle is valid, is for an
  1759. object of the specified type and has the specified accesses granted.
  1760. The handle's reference count is then incremented. If Lsa Database
  1761. locking is not requested, the Lsa Database must aready be locked.
  1762. If Lsa Database locking is requested, the Lsa Database must NOT be
  1763. locked.
  1764. Arguments:
  1765. ObjectHandle - Pointer to handle to be validated and referenced.
  1766. DesiredAccess - Specifies the accesses that are desired. The function
  1767. returns an error if any of the specified accesses have not been
  1768. granted.
  1769. HandleTypeId - Specifies the expected object type to which the handle
  1770. relates. An error is returned if this type does not match the
  1771. type contained in the handle.
  1772. ObjectTypeId - Specifies the expected object type to which the object that is to
  1773. be operated upon relates
  1774. Options - Specifies optional additional actions including database state
  1775. changes to be made, or actions not to be performed.
  1776. LSAP_DB_LOCK - Acquire the Lsa database lock. If this
  1777. flag is specified, the Lsa Database must NOT already be locked.
  1778. If this flag is not specified, the Lsa Database must already
  1779. be locked.
  1780. LSAP_DB_LOG_QUEUE_LOCK - Acquire the Lsa Audit Log Queue
  1781. Lock.
  1782. LSAP_DB_START_TRANSACTION - Start an Lsa database transaction.
  1783. NOTE: There may be some Options (not database states) provided in the
  1784. ObjectHandle. These options augment those provided.
  1785. Return Value:
  1786. NTSTATUS - Standard Nt Result Code
  1787. STATUS_INVALID_HANDLE - The handle could not be found.
  1788. STATUS_ACCESS_DENIED - Not all of the accesses specified have
  1789. been granted.
  1790. STATUS_OBJECT_TYPE_MISMATCH - The specified object type id does not
  1791. match the object type id contained in the handle.
  1792. STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources to
  1793. complete the command. An example is too many references to
  1794. the handle causing the count to overflow.
  1795. STATUS_BACKUP_CONTROLLER - A request to open a transaction has been
  1796. made by a non-trusted caller and the system is a Backup Domain
  1797. Controller. The LSA Database of a Backup Domain Controller
  1798. can only be updated by a trusted client, such as a replicator.
  1799. Result Codes from database transaction package.
  1800. --*/
  1801. {
  1802. NTSTATUS Status;
  1803. LSAP_DB_HANDLE InternalHandle = (LSAP_DB_HANDLE) ObjectHandle;
  1804. BOOLEAN GlobalSecret = FALSE;
  1805. ULONG States, EffectiveOptions;
  1806. ULONG ResetStates = 0;
  1807. BOOLEAN HandleReferenced = FALSE;
  1808. BOOLEAN StatesSet = FALSE;
  1809. LsapDsDebugOut(( DEB_FTRACE, "LsapDbReferenceObject\n" ));
  1810. //
  1811. // Search the list of handles for the given handle, validate the
  1812. // handle and verify that is for an object of the expected type.
  1813. // Augment the options passed in with those contained in the handle.
  1814. //
  1815. // Reference the handle.
  1816. //
  1817. Status = LsapDbVerifyHandle( ObjectHandle, 0, HandleTypeId, TRUE );
  1818. if (!NT_SUCCESS(Status)) {
  1819. ObjectHandle = NULL;
  1820. goto ReferenceError;
  1821. }
  1822. HandleReferenced = TRUE;
  1823. States = Options & LSAP_DB_STATE_MASK;
  1824. //
  1825. // Set the requested states before doing anything else. This ensures
  1826. // that the validity checks performed by this function are performed
  1827. // while the Lsa database is locked.
  1828. //
  1829. ResetStates |= ( States & ( LSAP_DB_READ_ONLY_TRANSACTION |
  1830. LSAP_DB_DS_OP_TRANSACTION ) );
  1831. if (States != 0) {
  1832. Status = LsapDbSetStates( States,
  1833. ObjectHandle,
  1834. ObjectTypeId );
  1835. if (!NT_SUCCESS(Status)) {
  1836. goto ReferenceError;
  1837. }
  1838. StatesSet = TRUE;
  1839. if (States & LSAP_DB_START_TRANSACTION) {
  1840. ResetStates |= LSAP_DB_FINISH_TRANSACTION;
  1841. }
  1842. if (States & LSAP_DB_LOCK) {
  1843. ResetStates |= LSAP_DB_LOCK;
  1844. }
  1845. if (States & LSAP_DB_LOG_QUEUE_LOCK) {
  1846. ResetStates |= LSAP_DB_LOG_QUEUE_LOCK;
  1847. }
  1848. }
  1849. //
  1850. // There may also be options set in the handle. Take these into
  1851. // account as well.
  1852. //
  1853. EffectiveOptions = Options | InternalHandle->Options;
  1854. //
  1855. // If the handle is not Trusted, verify that the desired accesses have been granted
  1856. //
  1857. if (!(InternalHandle->Trusted)) {
  1858. if (!RtlAreAllAccessesGranted( InternalHandle->GrantedAccess, DesiredAccess )) {
  1859. //
  1860. // Check to see if the caller is using authenticated RPC & they
  1861. // are failing because of POLICY_LOOKUP_NAME access
  1862. //
  1863. Status = STATUS_ACCESS_DENIED;
  1864. if ((InternalHandle->ObjectTypeId == PolicyObject) &&
  1865. RtlAreAllAccessesGranted(POLICY_LOOKUP_NAMES,DesiredAccess) &&
  1866. !RtlAreAllAccessesGranted(InternalHandle->GrantedAccess, POLICY_LOOKUP_NAMES) ) {
  1867. ULONG RpcErr;
  1868. ULONG AuthnLevel = 0;
  1869. ULONG AuthnSvc = 0;
  1870. RpcErr = RpcBindingInqAuthClient(
  1871. NULL,
  1872. NULL, // no privileges
  1873. NULL, // no server principal name
  1874. &AuthnLevel,
  1875. &AuthnSvc,
  1876. NULL // no authorization level
  1877. );
  1878. //
  1879. // If it as authenticated at level packet integrity or better
  1880. // and is done with the netlogon package, allow it through
  1881. //
  1882. if ((RpcErr == ERROR_SUCCESS) &&
  1883. (AuthnLevel >= RPC_C_AUTHN_LEVEL_PKT_INTEGRITY) &&
  1884. (AuthnSvc == RPC_C_AUTHN_NETLOGON )) {
  1885. Status = STATUS_SUCCESS;
  1886. }
  1887. }
  1888. if (!NT_SUCCESS(Status)) {
  1889. goto ReferenceError;
  1890. }
  1891. }
  1892. }
  1893. LsapDsDebugOut(( DEB_FTRACE, "LsapDbReferenceObject: 0x%lx\n", Status ));
  1894. return (Status);
  1895. ReferenceError:
  1896. //
  1897. // Unset the states in the correct order. If a database transaction
  1898. // was started by this routine, it will be aborted. Ignore the status
  1899. // No registry transaction can be active here
  1900. //
  1901. if (( ObjectHandle != NULL ) && (StatesSet)) {
  1902. LsapDbResetStates( ObjectHandle,
  1903. ResetStates,
  1904. ObjectTypeId,
  1905. ( SECURITY_DB_DELTA_TYPE )0,
  1906. Status );
  1907. }
  1908. //
  1909. // Dereference the handle if we referenced it.
  1910. //
  1911. if ( HandleReferenced ) {
  1912. LsapDbDereferenceHandle( ObjectHandle, FALSE );
  1913. }
  1914. LsapDsDebugOut(( DEB_FTRACE, "LsapDbReferenceObject: 0x%lx\n", Status ));
  1915. return Status;
  1916. }
  1917. NTSTATUS
  1918. LsapDbDereferenceObject(
  1919. IN OUT PLSAPR_HANDLE ObjectHandle,
  1920. IN LSAP_DB_OBJECT_TYPE_ID HandleTypeId,
  1921. IN LSAP_DB_OBJECT_TYPE_ID ObjectTypeId,
  1922. IN ULONG Options,
  1923. IN SECURITY_DB_DELTA_TYPE SecurityDbDeltaType,
  1924. IN NTSTATUS PreliminaryStatus
  1925. )
  1926. /*++
  1927. Routine Description:
  1928. This function dereferences a handle, optionally validating it first.
  1929. If the Reference Count in the handle goes to 0, the handle is freed.
  1930. The Lsa Database may optionally be unlocked by this function. It
  1931. must be locked before calling this function.
  1932. Arguments:
  1933. ObjectHandle - Pointer to handle to be dereferenced. If the reference
  1934. count reaches 0, NULL is returned in this location.
  1935. HandleTypeId - Specifies the expected object type to which the handle
  1936. relates. An error is returned if this type does not match the
  1937. type contained in the handle.
  1938. ObjectTypeId - Specifies the expected object type to which the object that is to
  1939. be operated upon relates
  1940. Options - Specifies optional additional actions to be performed including
  1941. Lsa Database states to be cleared.
  1942. LSAP_DB_VALIDATE_HANDLE - Validate the handle.
  1943. LSAP_DEREFERENCE_CONTR - Dereference the container object
  1944. LSAP_DB_FINISH_TRANSACTION - A database transaction was started
  1945. and must be concluded. Conclude the current Lsa Database
  1946. transaction by applying or aborting it depending on the
  1947. final Status.
  1948. LSAP_DB_LOCK - The Lsa database lock was acquired and
  1949. should be released.
  1950. LSAP_DB_LOG_QUEUE_LOCK - The Lsa Audit Log Queue Lock
  1951. was acquired and should be released.
  1952. LSAP_DB_OMIT_REPLICATOR_NOTIFICATION - Omit notification to
  1953. Replicator of the change.
  1954. LSAP_DB_ADMIT_DELETED_OBJECT_HANDLES - Permit the handle provided
  1955. to be for a deleted object.
  1956. NOTE: There may be some Options (not database states) provided in the
  1957. ObjectHandle. These options augment those provided.
  1958. PreliminaryStatus = Current Result Code.
  1959. Return Value:
  1960. NTSTATUS - Standard Nt Result Code
  1961. STATUS_INVALID_HANDLE - The handle could not be found.
  1962. STATUS_OBJECT_TYPE_MISMATCH - The specified object type id does not
  1963. match the object type id contained in the handle.
  1964. --*/
  1965. {
  1966. NTSTATUS Status, SecondaryStatus, TmpStatus;
  1967. LSAP_DB_HANDLE InternalHandle = (LSAP_DB_HANDLE) *ObjectHandle;
  1968. BOOLEAN DecrementCount = TRUE;
  1969. ULONG EffectiveOptions;
  1970. ULONG ReferenceCount = 0;
  1971. LsapDsDebugOut(( DEB_FTRACE, "LsapDbDereferenceObject\n" ));
  1972. Status = PreliminaryStatus;
  1973. SecondaryStatus = STATUS_SUCCESS;
  1974. //
  1975. // There may also be options set in the handle. Take these into
  1976. // account as well.
  1977. //
  1978. EffectiveOptions = Options | InternalHandle->Options;
  1979. //
  1980. // If validating, lookup the handle and match the type.
  1981. //
  1982. if (EffectiveOptions & LSAP_DB_VALIDATE_HANDLE) {
  1983. SecondaryStatus = LsapDbVerifyHandle(
  1984. *ObjectHandle,
  1985. EffectiveOptions,
  1986. HandleTypeId,
  1987. FALSE );
  1988. if (!NT_SUCCESS(SecondaryStatus)) {
  1989. DecrementCount = FALSE;
  1990. goto DereferenceObjectError;
  1991. }
  1992. }
  1993. //
  1994. // Dereference the container handle if so requested
  1995. //
  1996. if (EffectiveOptions & LSAP_DB_DEREFERENCE_CONTR) {
  1997. if (InternalHandle->ContainerHandle != NULL) {
  1998. //
  1999. // Dereference the container object.
  2000. //
  2001. SecondaryStatus = LsapDbDereferenceObject(
  2002. (PLSAPR_HANDLE) &InternalHandle->ContainerHandle,
  2003. NullObject,
  2004. NullObject,
  2005. LSAP_DB_READ_ONLY_TRANSACTION |
  2006. LSAP_DB_DS_OP_TRANSACTION |
  2007. LSAP_DB_STANDALONE_REFERENCE,
  2008. (SECURITY_DB_DELTA_TYPE) 0,
  2009. STATUS_SUCCESS
  2010. );
  2011. }
  2012. }
  2013. DereferenceObjectFinish:
  2014. //
  2015. // Unlock the database.
  2016. //
  2017. if (NT_SUCCESS(SecondaryStatus))
  2018. {
  2019. SecondaryStatus = LsapDbResetStates(
  2020. *ObjectHandle,
  2021. EffectiveOptions,
  2022. ObjectTypeId,
  2023. SecurityDbDeltaType,
  2024. Status
  2025. );
  2026. }
  2027. //
  2028. // Dereference the object handle
  2029. //
  2030. if ( DecrementCount ) {
  2031. //
  2032. // If the reference count reached zero,
  2033. // ditch to callers pointer to the handle.
  2034. //
  2035. if ( LsapDbDereferenceHandle( *ObjectHandle, NT_SUCCESS( Status ) ) ) {
  2036. *ObjectHandle = NULL;
  2037. }
  2038. }
  2039. if ( NT_SUCCESS( Status ) ) {
  2040. Status = SecondaryStatus;
  2041. }
  2042. LsapDsDebugOut(( DEB_FTRACE, "LsapDbDereferenceObject: 0x%lx\n", Status ));
  2043. return( Status );
  2044. DereferenceObjectError:
  2045. if (NT_SUCCESS(Status) && !NT_SUCCESS(SecondaryStatus)) {
  2046. Status = SecondaryStatus;
  2047. }
  2048. goto DereferenceObjectFinish;
  2049. }
  2050. NTSTATUS
  2051. LsapDbReadAttributeObject(
  2052. IN LSAPR_HANDLE ObjectHandle,
  2053. IN PUNICODE_STRING AttributeNameU,
  2054. IN OPTIONAL PVOID AttributeValue,
  2055. IN OUT PULONG AttributeValueLength
  2056. )
  2057. /*++
  2058. Routine Description:
  2059. This routine reads the value of an attribute of an open LSA Database object.
  2060. WARNING: The Lsa Database must be in the locked state when this function
  2061. is called and the supplied ObjectHandle must be valid.
  2062. Arguments:
  2063. ObjectHandle - LSA Handle to object. This must be valid.
  2064. AttributeNameU - Pointer to Unicode name of attribute
  2065. AttributeValue - Pointer to buffer to receive attribute's value. This
  2066. parameter may be NULL if the input AttributeValueLength is zero.
  2067. AttributeValueLength - Pointer to variable containing on input the size of
  2068. attribute value buffer and on output the size of the attributes's
  2069. value. A value of zero may be specified to indicate that the size of
  2070. the attribute's value is unknown.
  2071. Return Value:
  2072. NTSTATUS - Standard Nt Result Code
  2073. STATUS_BUFFER_OVERFLOW - This warning is returned if the specified
  2074. attribute value length is non-zero and too small for the
  2075. attribute's value.
  2076. --*/
  2077. {
  2078. //
  2079. // The LSA Database is implemented as a subtree of the Configuration
  2080. // Registry. In this implementation, Lsa Database objects correspond
  2081. // to Registry keys and "attributes" and their "values" correspond to
  2082. // Registry "subkeys" and "values" of the Registry key representing the
  2083. // object.
  2084. //
  2085. NTSTATUS Status = STATUS_SUCCESS;
  2086. //
  2087. // Verify that the LSA Database is locked
  2088. // (The lock for the specified object type must be locked.)
  2089. //
  2090. // ASSERT (LsapDbIsLocked());
  2091. Status = LsapRegReadAttribute( ObjectHandle,
  2092. AttributeNameU,
  2093. AttributeValue,
  2094. AttributeValueLength );
  2095. return(Status);
  2096. }
  2097. NTSTATUS
  2098. LsapDbReadAttributeObjectEx(
  2099. IN LSAPR_HANDLE ObjectHandle,
  2100. IN LSAP_DB_NAMES AttributeIndex,
  2101. IN OPTIONAL PVOID AttributeValue,
  2102. IN OUT PULONG AttributeValueLength,
  2103. IN BOOLEAN CanDefaultToZero
  2104. )
  2105. /*++
  2106. Routine Description:
  2107. This routine reads the value of an attribute of an open LSA Database object.
  2108. NOTE: This function obsolesces LsapDbReadAttributeObject
  2109. WARNING: The Lsa Database must be in the locked state when this function
  2110. is called and the supplied ObjectHandle must be valid.
  2111. Arguments:
  2112. ObjectHandle - LSA Handle to object. This must be valid.
  2113. AttributeIndex - Index into attribute list of attribute to be read
  2114. AttributeType - Type of the attribute
  2115. AttributeValue - Pointer to buffer to receive attribute's value. This
  2116. parameter may be NULL if the input AttributeValueLength is zero.
  2117. AttributeValueLength - Pointer to variable containing on input the size of
  2118. attribute value buffer and on output the size of the attributes's
  2119. value. A value of zero may be specified to indicate that the size of
  2120. the attribute's value is unknown.
  2121. Return Value:
  2122. NTSTATUS - Standard Nt Result Code
  2123. STATUS_BUFFER_OVERFLOW - This warning is returned if the specified
  2124. attribute value length is non-zero and too small for the
  2125. attribute's value.
  2126. --*/
  2127. {
  2128. //
  2129. // The LSA Database is implemented as a subtree of the Configuration
  2130. // Registry. In this implementation, Lsa Database objects correspond
  2131. // to Registry keys and "attributes" and their "values" correspond to
  2132. // Registry "subkeys" and "values" of the Registry key representing the
  2133. // object.
  2134. //
  2135. NTSTATUS Status = STATUS_SUCCESS;
  2136. LSAP_DB_ATTRIBUTE Attribute;
  2137. if ( !ARGUMENT_PRESENT( AttributeValueLength ) ) {
  2138. return( STATUS_INVALID_PARAMETER );
  2139. }
  2140. LsapDbInitializeAttributeDs(
  2141. &Attribute,
  2142. AttributeIndex,
  2143. AttributeValue,
  2144. AttributeValueLength ? *AttributeValueLength : 0,
  2145. FALSE
  2146. );
  2147. LsapDbAttributeCanNotExist( &Attribute );
  2148. //
  2149. // Verify that the LSA Database is locked
  2150. // (The lock for the specific object type must be locked.)
  2151. //
  2152. // ASSERT (LsapDbIsLocked());
  2153. Status = LsapDbReadAttributesObject( ObjectHandle,
  2154. 0,
  2155. &Attribute,
  2156. 1 );
  2157. if ( Status == STATUS_SUCCESS ) {
  2158. if ( ARGUMENT_PRESENT( AttributeValue ) ) {
  2159. if ( *AttributeValueLength >= Attribute.AttributeValueLength ) {
  2160. RtlCopyMemory( AttributeValue,
  2161. Attribute.AttributeValue,
  2162. Attribute.AttributeValueLength );
  2163. } else {
  2164. Status = STATUS_BUFFER_OVERFLOW;
  2165. }
  2166. }
  2167. *AttributeValueLength = Attribute.AttributeValueLength;
  2168. if ( Attribute.MemoryAllocated ) {
  2169. MIDL_user_free( Attribute.AttributeValue );
  2170. }
  2171. }
  2172. return(Status);
  2173. }
  2174. NTSTATUS
  2175. LsapDbWriteAttributeObject(
  2176. IN LSAPR_HANDLE ObjectHandle,
  2177. IN PUNICODE_STRING AttributeNameU,
  2178. IN PVOID AttributeValue,
  2179. IN ULONG AttributeValueLength
  2180. )
  2181. /*++
  2182. Routine Description:
  2183. This routine writes the value of an attribute of an open LSA Database
  2184. object. A Database transaction must already be open: the write is
  2185. appended to the transaction log.
  2186. WARNING: The Lsa Database must be in the locked state when this function
  2187. is called.
  2188. Arguments:
  2189. ObjectHandle - Lsa Handle of open object.
  2190. AttributeNameU - Pointer to Unicode string containing the name of the
  2191. attribute whose value is to be written.
  2192. AttributeValue - Pointer to buffer containing attribute's value. If NULL
  2193. is specified for this parameter, AttributeValueLength must be 0.
  2194. AttributeValueLength - Contains the size of attribute value buffer to be
  2195. written. 0 may be specified, indicating that the attribute is to be
  2196. deleted.
  2197. Return Value:
  2198. NTSTATUS - Standard Nt Result Code
  2199. STATUS_SUCCESS - The attribute was successfully added to the
  2200. transaction log.
  2201. STATUS_INVALID_PARAMETER - AttributeValue is NULL but the
  2202. AttributeValueLength value is not 0.
  2203. Errors from the Registry Transaction Package.
  2204. --*/
  2205. {
  2206. //
  2207. // The LSA Database is implemented as a subtree of the Configuration
  2208. // Registry. In this implementation, Lsa Database objects correspond
  2209. // to Registry keys and "attributes" and their "values" correspond to
  2210. // Registry "subkeys" and "values" of the Registry key representing the
  2211. // object.
  2212. //
  2213. NTSTATUS Status;
  2214. UNICODE_STRING PhysicalSubKeyNameU;
  2215. PhysicalSubKeyNameU.Buffer = NULL;
  2216. //
  2217. // Verify that the LSA Database is locked
  2218. // (The lock for the specified object type must be locked.)
  2219. //
  2220. // ASSERT (LsapDbIsLocked());
  2221. //
  2222. // If the attribute value is null, verify that the AttributeValueLength
  2223. // field is 0.
  2224. //
  2225. if (!ARGUMENT_PRESENT(AttributeValue)) {
  2226. if (AttributeValueLength != 0) {
  2227. Status = STATUS_INVALID_PARAMETER;
  2228. goto WriteAttributeObjectError;
  2229. }
  2230. }
  2231. //
  2232. // Writing an object attribute's value is more complex than reading
  2233. // one because the Registry Transaction package is called instead of
  2234. // calling the Registry API directly. Since the transaction package
  2235. // expects to perform its own open of the target subkey representing
  2236. // the attribute (when a transaction commit is finally done) using a
  2237. // name relative to the LSA Database Registry Transaction Key (which
  2238. // we call the Physical Name within the LSA Database code). The
  2239. // Registry Key handle contained in the object handle is therefore
  2240. // not used by the present routine. Instead, we need to construct the
  2241. // Physical Name the sub key and pass it together with the LSA Database
  2242. // Registry transaction key handle on the Registry transaction API
  2243. // call. The Physical Name of the subkey is constructed by
  2244. // concatenating the Physical Object Name stored in the object handle
  2245. // with a "\" and the given sub key name.
  2246. //
  2247. Status = LsapDbLogicalToPhysicalSubKey(
  2248. ObjectHandle,
  2249. &PhysicalSubKeyNameU,
  2250. AttributeNameU
  2251. );
  2252. if (!NT_SUCCESS(Status)) {
  2253. goto WriteAttributeObjectError;
  2254. }
  2255. //
  2256. // Now log the sub key write as a Registry Transaction
  2257. //
  2258. Status = LsapRegWriteAttribute(
  2259. &PhysicalSubKeyNameU,
  2260. AttributeValue,
  2261. AttributeValueLength
  2262. );
  2263. if (!NT_SUCCESS(Status)) {
  2264. goto WriteAttributeObjectError;
  2265. }
  2266. WriteAttributeObjectFinish:
  2267. //
  2268. // If necessary, free the Unicode String buffer allocated by
  2269. // LsapDbLogicalToPhysicalSubKey;
  2270. //
  2271. if (PhysicalSubKeyNameU.Buffer != NULL) {
  2272. RtlFreeUnicodeString(&PhysicalSubKeyNameU);
  2273. }
  2274. return(Status);
  2275. WriteAttributeObjectError:
  2276. goto WriteAttributeObjectFinish;
  2277. }
  2278. NTSTATUS
  2279. LsapDbWriteAttributesObject(
  2280. IN LSAPR_HANDLE ObjectHandle,
  2281. IN PLSAP_DB_ATTRIBUTE Attributes,
  2282. IN ULONG AttributeCount
  2283. )
  2284. /*++
  2285. Routine Description:
  2286. This routine writes the values of one or more attributes of an open LSA
  2287. Database object. A Database transaction must already be open: the write
  2288. is appended to the transaction log. The attribute names specified are
  2289. assumed to be consistent with the object type and the values supplied
  2290. are assumed to be valid.
  2291. WARNINGS: The Lsa Database must be in the locked state when this function
  2292. is called.
  2293. Arguments:
  2294. ObjectHandle - Lsa Handle of open object.
  2295. Attributes - Pointer to an array of Attribute Information blocks each
  2296. containing pointers to the attribute's Unicode Name, the value
  2297. to be stored, and the length of the value in bytes.
  2298. AttributeCount - Count of the attributes to be written, equivalently,
  2299. this is the number of elements of the array pointed to by Attributes.
  2300. Return Value:
  2301. NTSTATUS - Standard Nt Result Code
  2302. --*/
  2303. {
  2304. NTSTATUS Status = STATUS_SUCCESS;
  2305. ULONG Index, Options = 0;
  2306. LSAP_DB_HANDLE InternalHandle;
  2307. if ( !LsapDsIsWriteDs( ObjectHandle ) ) {
  2308. for(Index = 0; Index < AttributeCount; Index++) {
  2309. Status = LsapDbWriteAttributeObject(
  2310. ObjectHandle,
  2311. Attributes[Index].AttributeName,
  2312. Attributes[Index].AttributeValue,
  2313. Attributes[Index].AttributeValueLength
  2314. );
  2315. if (!NT_SUCCESS(Status)) {
  2316. break;
  2317. }
  2318. }
  2319. } else {
  2320. InternalHandle = ( LSAP_DB_HANDLE )ObjectHandle;
  2321. if ( InternalHandle->ObjectTypeId == SecretObject &&
  2322. FLAG_ON( InternalHandle->Options, LSAP_DB_HANDLE_CREATED_SECRET ) ) {
  2323. Options |= LSAPDS_REPL_CHANGE_URGENTLY;
  2324. }
  2325. Status = LsapDsWriteAttributes( &((LSAP_DB_HANDLE)ObjectHandle)->PhysicalNameDs,
  2326. Attributes,
  2327. AttributeCount,
  2328. Options);
  2329. if ( NT_SUCCESS( Status ) && FLAG_ON( Options, LSAPDS_REPL_CHANGE_URGENTLY ) ) {
  2330. InternalHandle->Options &= ~LSAP_DB_HANDLE_CREATED_SECRET;
  2331. }
  2332. }
  2333. return(Status);
  2334. }
  2335. NTSTATUS
  2336. LsapDbReadAttributesObject(
  2337. IN LSAPR_HANDLE ObjectHandle,
  2338. IN ULONG Options,
  2339. IN OUT PLSAP_DB_ATTRIBUTE Attributes,
  2340. IN ULONG AttributeCount
  2341. )
  2342. /*++
  2343. Routine Description:
  2344. This routine reads the values of one or more attributes of an open LSA
  2345. Database object. A Database transaction must already be open: the write
  2346. is appended to the transaction log. The attribute names specified are
  2347. assumed to be consistent with the object type and the values supplied
  2348. are assumed to be valid. This routine will allocate memory via
  2349. MIDL_user_allocate for buffers which will receive attribute values if
  2350. requested. This memory must be freed after use by calling MIDL_User_free
  2351. after use.
  2352. WARNINGS: The Lsa Database must be in the locked state when this function
  2353. is called.
  2354. Arguments:
  2355. ObjectHandle - Lsa Handle of open object.
  2356. Attributes - Pointer to an array of Attribute Information blocks each
  2357. containing pointers to the attribute's Unicode Name, an optional
  2358. pointer to a buffer that will receive the value and an optional
  2359. length of the value expected in bytes.
  2360. If the AttributeValue field in this structure is specified as non-NULL,
  2361. the attribute's data will be returned in the specified buffer. In
  2362. this case, the AttributeValueLength field must specify a sufficiently
  2363. large buffer size in bytes. If the specified size is too small,
  2364. a warning is returned and the buffer size required is returned in
  2365. AttributeValueLength.
  2366. If the AttributeValue field in this structure is NULL, the routine
  2367. will allocate memory for the attribute value's buffer, via MIDL_user_allocate(). If
  2368. the AttributeValueLength field is non-zero, the number of bytes specified
  2369. will be allocated. If the size of buffer allocated is too small to
  2370. hold the attribute's value, a warning is returned. If the
  2371. AttributeValuelength field is 0, the routine will first query the size
  2372. of buffer required and then allocate its memory.
  2373. In all success cases and buffer overflow cases, the
  2374. AttributeValueLength is set upon exit to the size of data required.
  2375. AttributeCount - Count of the attributes to be read, equivalently,
  2376. this is the number of elements of the array pointed to by Attributes.
  2377. Return Value:
  2378. NTSTATUS - Standard Nt Result Code
  2379. STATUS_SUCCESS - The call completed successfully.
  2380. STATUS_OBJECT_NAME_NOT_FOUND - One or more of the specified
  2381. attributes do not exist. In this case, the attribute information
  2382. AttributeValue, AttributeValueLength fields are zeroised. Note
  2383. that an attempt will be made to read all of the supplied
  2384. attributes, even if one of them is not found.
  2385. --*/
  2386. {
  2387. NTSTATUS Status = STATUS_SUCCESS;
  2388. PLSAP_DB_ATTRIBUTE NextAttribute = NULL;
  2389. BOOLEAN MemoryToFree = FALSE;
  2390. ULONG MemoryToFreeCount = 0;
  2391. if ( !LsapDsIsWriteDs(ObjectHandle) ) {
  2392. for (NextAttribute = Attributes;
  2393. NextAttribute < &Attributes[AttributeCount];
  2394. NextAttribute++) {
  2395. NextAttribute->MemoryAllocated = FALSE;
  2396. // If an explicit buffer pointer is given, verify that the length
  2397. // specified is non-zero and attempt to use that buffer.
  2398. //
  2399. if (NextAttribute->AttributeValue != NULL) {
  2400. if (NextAttribute->AttributeValueLength == 0) {
  2401. return(STATUS_INVALID_PARAMETER);
  2402. }
  2403. Status = LsapDbReadAttributeObject(
  2404. ObjectHandle,
  2405. NextAttribute->AttributeName,
  2406. (PVOID) NextAttribute->AttributeValue,
  2407. (PULONG) &NextAttribute->AttributeValueLength
  2408. );
  2409. if (!NT_SUCCESS(Status)) {
  2410. //
  2411. // If the attribute was not found, set the AttributeValue
  2412. // and AttributeValueLength fields to NULL and continue.
  2413. //
  2414. if (Status != STATUS_OBJECT_NAME_NOT_FOUND) {
  2415. break;
  2416. }
  2417. NextAttribute->AttributeValue = NULL;
  2418. NextAttribute->AttributeValueLength = 0;
  2419. }
  2420. continue;
  2421. }
  2422. //
  2423. // No output buffer pointer has been given. If a zero buffer
  2424. // size is given, query size of memory required. Since the
  2425. // buffer length is 0, STATUS_SUCCESS should be returned rather
  2426. // than STATUS_BUFFER_OVERFLOW.
  2427. //
  2428. if (NextAttribute->AttributeValueLength == 0) {
  2429. Status = LsapDbReadAttributeObject(
  2430. ObjectHandle,
  2431. NextAttribute->AttributeName,
  2432. NULL,
  2433. (PULONG) &NextAttribute->AttributeValueLength
  2434. );
  2435. if (!NT_SUCCESS(Status)) {
  2436. //
  2437. // If the attribute was not found, set the AttributeValue
  2438. // and AttributeValueLength fields to NULL and continue.
  2439. //
  2440. if (Status != STATUS_OBJECT_NAME_NOT_FOUND) {
  2441. break;
  2442. }
  2443. NextAttribute->AttributeValue = NULL;
  2444. NextAttribute->AttributeValueLength = 0;
  2445. continue;
  2446. }
  2447. Status = STATUS_SUCCESS;
  2448. }
  2449. //
  2450. // If the attribute value size needed is 0, return NULL pointer
  2451. //
  2452. if (NextAttribute->AttributeValueLength == 0) {
  2453. NextAttribute->AttributeValue = NULL;
  2454. continue;
  2455. }
  2456. //
  2457. // Allocate memory for the buffer.
  2458. //
  2459. NextAttribute->AttributeValue =
  2460. MIDL_user_allocate(NextAttribute->AttributeValueLength);
  2461. if (NextAttribute->AttributeValue == NULL) {
  2462. Status = STATUS_INSUFFICIENT_RESOURCES;
  2463. break;
  2464. }
  2465. NextAttribute->MemoryAllocated = TRUE;
  2466. MemoryToFree = TRUE;
  2467. MemoryToFreeCount++;
  2468. //
  2469. // Now read the attribute into the buffer.
  2470. //
  2471. Status = LsapDbReadAttributeObject(
  2472. ObjectHandle,
  2473. NextAttribute->AttributeName,
  2474. (PVOID) NextAttribute->AttributeValue,
  2475. (PULONG) &NextAttribute->AttributeValueLength
  2476. );
  2477. if (!NT_SUCCESS(Status)) {
  2478. break;
  2479. }
  2480. }
  2481. if (!NT_SUCCESS(Status)) {
  2482. goto ReadAttributesError;
  2483. }
  2484. } else {
  2485. //
  2486. // Use the DS method to read them all at once
  2487. //
  2488. Status = LsapDsReadAttributes( &((LSAP_DB_HANDLE)ObjectHandle)->PhysicalNameDs,
  2489. LSAPDS_OP_NO_LOCK,
  2490. Attributes,
  2491. AttributeCount );
  2492. }
  2493. ReadAttributesFinish:
  2494. return(Status);
  2495. ReadAttributesError:
  2496. //
  2497. // If memory was allocated for any values read, it must be freed.
  2498. //
  2499. if (MemoryToFree) {
  2500. for (NextAttribute = &Attributes[0];
  2501. (MemoryToFreeCount > 0) &&
  2502. (NextAttribute < &Attributes[AttributeCount]);
  2503. NextAttribute++) {
  2504. if (NextAttribute->MemoryAllocated) {
  2505. MIDL_user_free( NextAttribute->AttributeValue );
  2506. NextAttribute->AttributeValue = NULL;
  2507. MemoryToFreeCount--;
  2508. }
  2509. }
  2510. }
  2511. goto ReadAttributesFinish;
  2512. }
  2513. NTSTATUS
  2514. LsapDbDeleteAttributeObject(
  2515. IN LSAPR_HANDLE ObjectHandle,
  2516. IN PUNICODE_STRING AttributeNameU,
  2517. IN BOOLEAN DeleteSecurely
  2518. )
  2519. /*++
  2520. Routine Description:
  2521. This routine deletes an attribute of an open LSA Database object.
  2522. A Database transaction must already be open: the delete actions are
  2523. appended to the transaction log.
  2524. WARNING: The Lsa Database must be in the locked state when this function
  2525. is called.
  2526. The LSA Database is implemented as a subtree of the Configuration
  2527. Registry. In this implementation, Lsa Database objects correspond
  2528. to Registry keys and "attributes" and their "values" correspond to
  2529. Registry "subkeys" and "values" of the Registry key representing the
  2530. object.
  2531. Arguments:
  2532. ObjectHandle - Lsa Handle of open object.
  2533. AttributeNameU - Pointer to Unicode string containing the name of the
  2534. attribute whose value is to be written.
  2535. Return Value:
  2536. NTSTATUS - Standard Nt Result Code
  2537. --*/
  2538. {
  2539. NTSTATUS Status;
  2540. UNICODE_STRING PhysicalSubKeyNameU;
  2541. ULONG AttributeLength = 0;
  2542. //
  2543. // Verify that the LSA Database is locked
  2544. // (The lock for the specified object type must be locked.)
  2545. //
  2546. // ASSERT (LsapDbIsLocked());
  2547. //
  2548. // The Registry code will actually create a key if one does not exist, so
  2549. // probe for the existence of the key first.
  2550. //
  2551. Status = LsapDbReadAttributeObject(
  2552. ObjectHandle,
  2553. AttributeNameU,
  2554. NULL,
  2555. &AttributeLength
  2556. );
  2557. if (!NT_SUCCESS(Status)) {
  2558. goto DeleteAttributeObjectError;
  2559. }
  2560. //
  2561. // We need to construct the Physical Name the sub key relative
  2562. // to the LSA Database root node in the Registry. This is done by
  2563. // concatenating the Physical Object Name stored in the object handle with
  2564. // a "\" and the given sub key name.
  2565. //
  2566. Status = LsapDbLogicalToPhysicalSubKey(
  2567. ObjectHandle,
  2568. &PhysicalSubKeyNameU,
  2569. AttributeNameU
  2570. );
  2571. if (!NT_SUCCESS(Status)) {
  2572. goto DeleteAttributeObjectError;
  2573. }
  2574. //
  2575. // Now log the sub key write as a Registry Transaction
  2576. //
  2577. Status = LsapRegDeleteAttribute(
  2578. &PhysicalSubKeyNameU,
  2579. DeleteSecurely,
  2580. AttributeLength
  2581. );
  2582. RtlFreeUnicodeString(&PhysicalSubKeyNameU);
  2583. if (!NT_SUCCESS(Status)) {
  2584. goto DeleteAttributeObjectError;
  2585. }
  2586. DeleteAttributeObjectFinish:
  2587. return(Status);
  2588. DeleteAttributeObjectError:
  2589. //
  2590. // Add any cleanup required on error paths only here.
  2591. //
  2592. goto DeleteAttributeObjectFinish;
  2593. }
  2594. NTSTATUS
  2595. LsapDbDeleteAttributesObject(
  2596. IN LSAPR_HANDLE ObjectHandle,
  2597. IN PLSAP_DB_ATTRIBUTE Attributes,
  2598. IN ULONG AttributeCount
  2599. )
  2600. /*++
  2601. Routine Description:
  2602. This routine deletes the values of one or more attributes of an open LSA
  2603. Database object. A Database transaction must already be open: the write
  2604. is appended to the transaction log. The attribute names specified are
  2605. assumed to be consistent with the object type and the values supplied
  2606. are assumed to be valid.
  2607. WARNINGS: The Lsa Database must be in the locked state when this function
  2608. is called.
  2609. Arguments:
  2610. ObjectHandle - Lsa Handle of open object.
  2611. Attributes - Pointer to an array of Attribute Information blocks each
  2612. containing pointers to the attribute's Unicode Name, the value
  2613. to be stored, and the length of the value in bytes.
  2614. AttributeCount - Count of the attributes to be written, equivalently,
  2615. this is the number of elements of the array pointed to by Attributes.
  2616. Return Value:
  2617. NTSTATUS - Standard Nt Result Code
  2618. --*/
  2619. {
  2620. NTSTATUS Status = STATUS_SUCCESS;
  2621. ULONG Index;
  2622. if ( !LsapDsIsWriteDs( ObjectHandle ) ) {
  2623. for(Index = 0; Index < AttributeCount; Index++) {
  2624. Status = LsapDbDeleteAttributeObject(
  2625. ObjectHandle,
  2626. Attributes[Index].AttributeName,
  2627. FALSE
  2628. );
  2629. if (!NT_SUCCESS(Status)) {
  2630. break;
  2631. }
  2632. }
  2633. } else {
  2634. Status = LsapDsDeleteAttributes( &((LSAP_DB_HANDLE)ObjectHandle)->PhysicalNameDs,
  2635. Attributes,
  2636. AttributeCount);
  2637. }
  2638. return(Status);
  2639. }
  2640. typedef NTSTATUS ( *LsapDsPolicyNotify )(
  2641. IN SECURITY_DB_TYPE DbType,
  2642. IN SECURITY_DB_DELTA_TYPE DeltaType,
  2643. IN SECURITY_DB_OBJECT_TYPE ObjectType,
  2644. IN PSID ObjectSid
  2645. );
  2646. NTSTATUS
  2647. LsapSceNotify(
  2648. IN SECURITY_DB_DELTA_TYPE DeltaType,
  2649. IN SECURITY_DB_OBJECT_TYPE ObjectType,
  2650. IN PSID ObjectSid OPTIONAL
  2651. )
  2652. {
  2653. NTSTATUS Status;
  2654. NTSTATUS SavedStatus = STATUS_SUCCESS;
  2655. static LsapDsPolicyNotify SceNotify = NULL;
  2656. static HANDLE DllHandle = NULL;
  2657. static LARGE_INTEGER liZero = {0};
  2658. ASSERT( !g_ScePolicyLocked );
  2659. if ( !LsapDbState.ReplicatorNotificationEnabled ) {
  2660. return STATUS_SUCCESS;
  2661. }
  2662. if ( SceNotify == NULL ) {
  2663. if ( DllHandle != NULL ) {
  2664. FreeLibrary( DllHandle );
  2665. DllHandle = NULL;
  2666. }
  2667. DllHandle = LoadLibraryA( "scecli" );
  2668. if ( DllHandle == NULL ) {
  2669. LsapDsDebugOut(( DEB_ERROR, "Failed to load SCECLI.DLL\n" ));
  2670. if ( NT_SUCCESS(SavedStatus)) {
  2671. SavedStatus = STATUS_DLL_NOT_FOUND;
  2672. }
  2673. } else {
  2674. SceNotify = ( LsapDsPolicyNotify )GetProcAddress( DllHandle,
  2675. "SceNotifyPolicyDelta" );
  2676. if ( SceNotify == NULL ) {
  2677. LsapDsDebugOut(( DEB_ERROR,
  2678. "Failed to find SceNotifyPolicyDelta in SCECLI.DLL\n" ));
  2679. if ( NT_SUCCESS(SavedStatus)) {
  2680. SavedStatus = STATUS_ENTRYPOINT_NOT_FOUND;
  2681. }
  2682. }
  2683. }
  2684. }
  2685. //
  2686. // The only two types of objects SCE cares about are Policy and Account objects
  2687. //
  2688. switch ( ObjectType ) {
  2689. case SecurityDbObjectLsaPolicy:
  2690. case SecurityDbObjectLsaAccount:
  2691. break;
  2692. default:
  2693. //
  2694. // Shouldn't call this routine with other object types
  2695. //
  2696. ASSERT( FALSE );
  2697. return STATUS_SUCCESS;
  2698. }
  2699. if ( SceNotify != NULL ) {
  2700. Status = ( *SceNotify )(
  2701. SecurityDbLsa,
  2702. DeltaType,
  2703. ObjectType,
  2704. ObjectSid );
  2705. if ( !NT_SUCCESS( Status ) ) {
  2706. if ( NT_SUCCESS(SavedStatus)) {
  2707. SavedStatus = Status;
  2708. }
  2709. }
  2710. }
  2711. return SavedStatus;
  2712. }
  2713. NTSTATUS
  2714. LsapNetNotifyDelta (
  2715. IN SECURITY_DB_TYPE DbType,
  2716. IN LARGE_INTEGER SerialNumber,
  2717. IN SECURITY_DB_DELTA_TYPE DeltaType,
  2718. IN SECURITY_DB_OBJECT_TYPE ObjectType,
  2719. IN ULONG ObjectRid,
  2720. IN PSID ObjectSid,
  2721. IN PUNICODE_STRING ObjectName,
  2722. IN DWORD ReplicateImmediately,
  2723. IN PSAM_DELTA_DATA MemberId
  2724. )
  2725. /*++
  2726. Routine Description:
  2727. This is a wrapper function for Netlogon's I_NetNotifyDelta
  2728. Arguments:
  2729. Same as I_NetNotifyDelta
  2730. Return Value:
  2731. Same as I_NetNotifyDelta
  2732. --*/
  2733. {
  2734. //
  2735. // Notify the LSA Database Replicator of the change.
  2736. //
  2737. return ( I_NetNotifyDelta(
  2738. DbType,
  2739. SerialNumber,
  2740. DeltaType,
  2741. ObjectType,
  2742. ObjectRid,
  2743. ObjectSid,
  2744. ObjectName,
  2745. ReplicateImmediately,
  2746. MemberId ));
  2747. }
  2748. NTSTATUS
  2749. LsapDbNotifyChangeObject(
  2750. IN LSAPR_HANDLE ObjectHandle,
  2751. IN SECURITY_DB_DELTA_TYPE SecurityDbDeltaType
  2752. )
  2753. /*++
  2754. Routine Description:
  2755. This function notifies the LSA Database Replicator (if any) of a
  2756. change to an object. Change notifications for Secret objects specify
  2757. that replication of the change should occur immediately.
  2758. WARNING! All parameters passed to this routine are assumed valid.
  2759. No checking will be done.
  2760. Must be entered with the RegistryLock locked.
  2761. Arguments:
  2762. ObjectHandle - Handle to an LSA object. This is expected to have
  2763. already been validated.
  2764. SecurityDbDeltaType - Specifies the type of change being made. The
  2765. following values only are relevant:
  2766. SecurityDbNew - Indicates that a new object has been created.
  2767. SecurityDbDelete - Indicates that an object is being deleted.
  2768. SecurityDbChange - Indicates that the attributes of an object
  2769. are being changed, including creation or deletion of
  2770. attributes.
  2771. Return Values:
  2772. NTSTATUS - Standard Nt Result Code.
  2773. STATUS_SUCCESS - The call completed successfully.
  2774. STATUS_INVALID_HANDLE - The specified handle is invalid. This
  2775. error is only returned if the Object Type Id in the handle
  2776. is invalid.
  2777. STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources,
  2778. such as memory, to complete the call.
  2779. --*/
  2780. {
  2781. NTSTATUS Status = STATUS_SUCCESS;
  2782. SECURITY_DB_OBJECT_TYPE ObjectType = SecurityDbObjectLsaTDomain;
  2783. UNICODE_STRING ObjectName;
  2784. PSID ObjectSid = NULL;
  2785. ULONG ObjectRid = 0;
  2786. UCHAR SubAuthorityCount;
  2787. LSAP_DB_HANDLE InternalHandle = (LSAP_DB_HANDLE) ObjectHandle;
  2788. BOOLEAN ReplicateImmediately = FALSE;
  2789. ASSERT( LsapDbIsLocked( &LsapDbState.RegistryLock ));
  2790. ObjectName.Buffer = NULL;
  2791. ObjectName.Length = ObjectName.MaximumLength = 0;
  2792. ASSERT(LsapDbState.ReplicatorNotificationEnabled);
  2793. //
  2794. // The problem is that many code paths in the lsa pass a 0 for SecurityDbDeltaType.
  2795. // without specifying omit replicator notification. This is incorrect and causes
  2796. // a notification with a 0 specified for the delta type. This is causes a full
  2797. // sync of all NT4 BDC's. To safegaurd against this case
  2798. ASSERT(SecurityDbDeltaType!=0);
  2799. if (0==SecurityDbDeltaType)
  2800. {
  2801. SecurityDbDeltaType = SecurityDbChange;
  2802. }
  2803. //
  2804. // Convert the Lsa Database Object Type to a Database Delta Type.
  2805. //
  2806. switch (InternalHandle->ObjectTypeId) {
  2807. case PolicyObject:
  2808. ObjectType = SecurityDbObjectLsaPolicy;
  2809. break;
  2810. case AccountObject:
  2811. ObjectType = SecurityDbObjectLsaAccount;
  2812. break;
  2813. case TrustedDomainObject:
  2814. ObjectType = SecurityDbObjectLsaTDomain;
  2815. break;
  2816. case SecretObject:
  2817. ObjectType = SecurityDbObjectLsaSecret;
  2818. ReplicateImmediately = TRUE;
  2819. break;
  2820. default:
  2821. Status = STATUS_INVALID_HANDLE;
  2822. goto Cleanup;
  2823. }
  2824. //
  2825. // Get the Name or Sid of the object from its handle. If the object
  2826. // is of a type such as SecretObject that is accessed by Name, then
  2827. // the object's externally known name is equal to its internal
  2828. // Logical Name contained in the handle.
  2829. //
  2830. if ( LsapDbAccessedBySidObject( InternalHandle->ObjectTypeId )) {
  2831. ObjectSid = InternalHandle->Sid;
  2832. if ( InternalHandle->ObjectTypeId != TrustedDomainObject ) {
  2833. ASSERT( ObjectSid );
  2834. if ( ObjectSid == NULL ) {
  2835. Status = STATUS_INVALID_SID;
  2836. goto Cleanup;
  2837. }
  2838. SubAuthorityCount = *RtlSubAuthorityCountSid( ObjectSid );
  2839. ObjectRid = *RtlSubAuthoritySid( ObjectSid, SubAuthorityCount -1 );
  2840. }
  2841. } else if (LsapDsIsWriteDs( InternalHandle) ||
  2842. LsapDbAccessedByNameObject( InternalHandle->ObjectTypeId )) {
  2843. Status = LsapRpcCopyUnicodeString(
  2844. NULL,
  2845. &ObjectName,
  2846. &InternalHandle->LogicalNameU
  2847. );
  2848. if (!NT_SUCCESS(Status)) {
  2849. goto Cleanup;
  2850. }
  2851. } else {
  2852. //
  2853. // Currently, an object is either accessed by Sid or by Name, so
  2854. // something is wrong if both of the above chacks have failed.
  2855. //
  2856. Status = STATUS_INVALID_HANDLE;
  2857. goto Cleanup;
  2858. }
  2859. //
  2860. // Notify the LSA Database Replicator of the change.
  2861. //
  2862. Status = LsapNetNotifyDelta (
  2863. SecurityDbLsa,
  2864. LsapDbState.PolicyModificationInfo.ModifiedId,
  2865. SecurityDbDeltaType,
  2866. ObjectType,
  2867. ObjectRid,
  2868. ObjectSid,
  2869. &ObjectName,
  2870. ReplicateImmediately,
  2871. NULL
  2872. );
  2873. Cleanup:
  2874. //
  2875. // If we allocated memory for the Object Name Unicode buffer, free it.
  2876. //
  2877. if (ObjectName.Buffer != NULL) {
  2878. MIDL_user_free( ObjectName.Buffer );
  2879. }
  2880. //
  2881. // Suppress any error and return STATUS_SUCCESS. Currently, there is
  2882. // no meaningful action an LSA client of this routine can take.
  2883. //
  2884. return STATUS_SUCCESS;
  2885. }
  2886. NTSTATUS
  2887. LsapDbVerifyInformationObject(
  2888. IN PLSAP_DB_OBJECT_INFORMATION ObjectInformation
  2889. )
  2890. /*++
  2891. Routine Description:
  2892. This function verifies that the information specified in passed
  2893. ObjectInformation is syntactically valid.
  2894. Arguments:
  2895. ObjectInformation - Pointer to information describing this object. The
  2896. following information items must be specified:
  2897. o Object Type Id
  2898. o Object Logical Name (as ObjectAttributes->ObjectName, a pointer to
  2899. a Unicode string)
  2900. o Container object handle (for any object except the root Policy object).
  2901. All other fields in ObjectAttributes portion of ObjectInformation
  2902. such as SecurityDescriptor are ignored.
  2903. Return Value:
  2904. NTSTATUS - Standard Nt Result Code
  2905. STATUS_INVALID_PARAMETER - Invalid object information given
  2906. - ObjectInformation is NULL
  2907. - Object Type Id is out of range
  2908. - No Logical Name pointer given
  2909. - Logical Name not a pointer to a Unicode String (TBS)
  2910. --*/
  2911. {
  2912. NTSTATUS Status = STATUS_SUCCESS;
  2913. LSAP_DB_OBJECT_TYPE_ID ObjectTypeId = ObjectInformation->ObjectTypeId;
  2914. //
  2915. // Verify that ObjectInformation is given
  2916. //
  2917. if (!ARGUMENT_PRESENT(ObjectInformation)) {
  2918. return(STATUS_INVALID_PARAMETER);
  2919. }
  2920. //
  2921. // Validate the Object Type Id. It must be in range.
  2922. //
  2923. if (!LsapDbIsValidTypeObject(ObjectTypeId)) {
  2924. return(STATUS_INVALID_PARAMETER);
  2925. }
  2926. //
  2927. // Verify that a Logical Name is given. A pointer to a Unicode string
  2928. // is expected.
  2929. //
  2930. if (!ARGUMENT_PRESENT(ObjectInformation->ObjectAttributes.ObjectName)) {
  2931. Status = STATUS_INVALID_PARAMETER;
  2932. }
  2933. return(Status);
  2934. }
  2935. NTSTATUS
  2936. LsapDbSidToLogicalNameObject(
  2937. IN PSID Sid,
  2938. OUT PUNICODE_STRING LogicalNameU
  2939. )
  2940. /*++
  2941. Routine Description:
  2942. This function generates the Logical Name (Internal LSA Database Name)
  2943. of an object from its Sid. Currently, only the Relative Id (lowest
  2944. sub-authority) is used due to Registry and hence Lsa Database limits
  2945. on name components to 8 characters. The Rid is extracted and converted
  2946. to an 8-digit Unicode Integer.
  2947. Arguments:
  2948. Sid - Pointer to the Sid to be looked up. It is the caller's
  2949. responsibility to ensure that the Sid has valid syntax.
  2950. LogicalNameU - Pointer to a Unicode String structure that will receive
  2951. the Logical Name. Note that memory for the string buffer in this
  2952. Unicode String will be allocated by this routine if successful. The
  2953. caller must free this memory after use by calling RtlFreeUnicodeString.
  2954. Return Value:
  2955. NTSTATUS - Standard Nt Status code
  2956. STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources
  2957. to allocate buffer for Unicode String name.
  2958. --*/
  2959. {
  2960. NTSTATUS Status;
  2961. //
  2962. // First, verify that the given Sid is valid
  2963. //
  2964. if (!RtlValidSid( Sid )) {
  2965. return STATUS_INVALID_PARAMETER;
  2966. }
  2967. Status = RtlConvertSidToUnicodeString( LogicalNameU, Sid, TRUE);
  2968. return Status;
  2969. }
  2970. NTSTATUS
  2971. LsapDbGetNamesObject(
  2972. IN PLSAP_DB_OBJECT_INFORMATION ObjectInformation,
  2973. IN ULONG CreateHandleOptions,
  2974. OUT OPTIONAL PUNICODE_STRING LogicalNameU,
  2975. OUT OPTIONAL PUNICODE_STRING PhysicalNameU,
  2976. OUT OPTIONAL PUNICODE_STRING PhysicalNameDs
  2977. )
  2978. /*++
  2979. Routine Description:
  2980. This function returns the Logical and/or Physical Names of an object
  2981. given an object information buffer. Memory will be allocated for
  2982. the Unicode String Buffers that will receive the name(s).
  2983. The Logical Name of an object is the path of the object within the
  2984. LSA Database relative to its Classifying Directory. The Logical Name
  2985. of an object is implemntation-dependent and on current implementations
  2986. is equal to one of the following depending on object type:
  2987. o The External Name of the object (if any)
  2988. o The Relative Id (lowest sub-authority) in the object's Sid (if any)
  2989. converted to an 8-digit integer, including leading 0's added as
  2990. padding.
  2991. The Physical Name of an object is the full path of the object relative
  2992. to the root ot the Database. It is computed by concatenating the Physical
  2993. Name of the Container Object (if any), the Classifying Directory
  2994. corresponding to the object type id, and the Logical Name of the
  2995. object.
  2996. <Physical Name of Object> =
  2997. [<Physical Name of Container Object> "\"]
  2998. [<Classifying Directory> "\"] <Logical Name of Object>
  2999. If there is no Container Object (as in the case of the Policy object)
  3000. the <Physical Name of Container Object> and following \ are omitted.
  3001. If there is no Classifying Directory (as in the case of the Policy object)
  3002. the <Classifying Directory> and following \ are omitted. If neither
  3003. Container Object not Classifying Directory exist, the Logical and Physical
  3004. names coincide.
  3005. Note that memory is allocated by this routine for the output
  3006. Unicode string buffer(s). When the output Unicode String(s) are no
  3007. longer needed, the memory must be freed by call(s) to
  3008. RtlFreeUnicodeString().
  3009. Example of Physical Name computation:
  3010. Consider the user or group account object ScottBi
  3011. Container Object Logical Name: Policy
  3012. Container Object Physical Name: Policy (no Classifying Directory or
  3013. Container Object exists)
  3014. Classifying Directory for ScottBi: Accounts
  3015. Logical Name of Object: ScottBi
  3016. Physical Name of Object Policy\Accounts\ScottBi
  3017. Note that the Physical Name is exactly the Registry path relative to
  3018. the Security directory.
  3019. WARNING: The Lsa Database must be in the locked state when this function
  3020. is called.
  3021. Arguments:
  3022. ObjectInformation - Pointer to object information containing as a minimum
  3023. the object's Logical Name, Container Object's handle and object type
  3024. id.
  3025. LogicalNameU - Optional pointer to Unicode String structure which will
  3026. receive the Logical Name of the object. A buffer will be allocated
  3027. by this routine for the name text. This memory must be freed when no
  3028. longer needed by calling RtlFreeUnicodeString() wiht a pointer such
  3029. as LogicalNameU to the Unicode String structure.
  3030. PhysicalNameU - Optional pointer to Unicode String structure which will
  3031. receive the Physical Name of the object. A buffer will be allocated by
  3032. this routine for the name text. This memory must be freed when no
  3033. longer needed by calling RtlFreeUnicodeString() with a pointer such as
  3034. PhysicalNameU to the Unicode String structure. This is only initialized
  3035. the object can reside in the registry
  3036. PhysicalNameDs - Optional pointer to Unicode String structure which will
  3037. receive the Physical Name of the object if it resides in the DS. Same
  3038. caveats apply.
  3039. Return Value:
  3040. NTSTATUS - Standard Nt Result Code
  3041. STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources to
  3042. allocate the name string buffer for the Physical Name or
  3043. Logical Name.
  3044. --*/
  3045. {
  3046. NTSTATUS Status = STATUS_SUCCESS;
  3047. PUNICODE_STRING ContainerPhysicalNameU = NULL;
  3048. PUNICODE_STRING ClassifyingDirU = NULL;
  3049. UNICODE_STRING IntermediatePath1U;
  3050. PUNICODE_STRING JoinedPath1U = &IntermediatePath1U;
  3051. LSAP_DB_OBJECT_TYPE_ID ObjectTypeId = ObjectInformation->ObjectTypeId;
  3052. POBJECT_ATTRIBUTES ObjectAttributes = &ObjectInformation->ObjectAttributes;
  3053. UNICODE_STRING TempLogicalNameU, TempDomainLogicalName;
  3054. UUID Uuid;
  3055. PWSTR GuidString;
  3056. RPC_STATUS RpcStatus;
  3057. ULONG GuidLength, BufferLength, SkipLength;
  3058. PBYTE ScratchBuffer = NULL, CopyStart;
  3059. BOOLEAN ObjectShouldExist = TRUE;
  3060. //
  3061. // Initialize
  3062. //
  3063. RtlInitUnicodeString( &IntermediatePath1U, NULL );
  3064. RtlInitUnicodeString( &TempLogicalNameU, NULL );
  3065. RtlInitUnicodeString( &TempDomainLogicalName, NULL );
  3066. //
  3067. // Verify that the LSA Database is locked
  3068. // (The lock for the specified object type must be locked.)
  3069. //
  3070. // ASSERT (LsapDbIsLocked());
  3071. //
  3072. // Capture the Logical Name of the object into permanent memory.
  3073. //
  3074. LSAPDS_ALLOC_AND_COPY_UNICODE_STRING_ON_SUCCESS( Status,
  3075. &TempLogicalNameU,
  3076. ObjectInformation->ObjectAttributes.ObjectName );
  3077. if (!NT_SUCCESS(Status)) {
  3078. goto Cleanup;
  3079. }
  3080. //
  3081. // If the Logical Name of the object is requested, return this.
  3082. //
  3083. if (ARGUMENT_PRESENT(LogicalNameU)) {
  3084. *LogicalNameU = TempLogicalNameU;
  3085. }
  3086. //
  3087. // If the Physical Name of the object is not required, just return.
  3088. //
  3089. if (ARGUMENT_PRESENT(PhysicalNameU)) {
  3090. PhysicalNameU->Buffer = NULL;
  3091. Status = LsapRegGetPhysicalObjectName(
  3092. ObjectInformation,
  3093. &TempLogicalNameU,
  3094. PhysicalNameU );
  3095. }
  3096. if ( NT_SUCCESS( Status ) && ARGUMENT_PRESENT( PhysicalNameDs) ) {
  3097. PhysicalNameDs->Buffer = NULL;
  3098. //
  3099. // Copy the logical name, in case we have to return the current copy...
  3100. //
  3101. LSAPDS_ALLOC_AND_COPY_UNICODE_STRING_ON_SUCCESS( Status,
  3102. &TempDomainLogicalName,
  3103. &TempLogicalNameU );
  3104. if ( !NT_SUCCESS( Status ) ) {
  3105. goto Cleanup;
  3106. }
  3107. if ( FLAG_ON( CreateHandleOptions, LSAP_DB_CREATE_HANDLE_MORPH ) ) {
  3108. ObjectShouldExist = FALSE;
  3109. }
  3110. //
  3111. // If the name is too long, truncate it...
  3112. //
  3113. if ( FLAG_ON( CreateHandleOptions, LSAP_DB_CREATE_HANDLE_MORPH ) ) {
  3114. LsapTruncateUnicodeString( &TempDomainLogicalName, MAX_RDN_KEY_SIZE );
  3115. }
  3116. Status = LsapDsGetPhysicalObjectName( ObjectInformation,
  3117. ObjectShouldExist,
  3118. &TempDomainLogicalName,
  3119. PhysicalNameDs );
  3120. if ( (Status == STATUS_OBJECT_NAME_COLLISION) &&
  3121. (ObjectInformation->ObjectTypeId == NewTrustedDomainObject) &&
  3122. FLAG_ON( CreateHandleOptions, LSAP_DB_CREATE_HANDLE_MORPH ) ) {
  3123. //
  3124. // Got a name collion. Morph the name by replacing the last digits with a GUID
  3125. //
  3126. RpcStatus = UuidCreate ( &Uuid );
  3127. if ( RpcStatus == RPC_S_OK || RpcStatus == RPC_S_UUID_LOCAL_ONLY ) {
  3128. Status = STATUS_SUCCESS;
  3129. RpcStatus = UuidToStringW( &Uuid, &GuidString );
  3130. if ( RpcStatus == RPC_S_OK ) {
  3131. GuidLength = wcslen( GuidString );
  3132. //
  3133. // Now, we have to handle the cases of the various string lengths...
  3134. //
  3135. BufferLength = 0;
  3136. if ( ( TempDomainLogicalName.Length / sizeof( WCHAR ) ) + GuidLength >=
  3137. MAX_RDN_KEY_SIZE ) {
  3138. LsapTruncateUnicodeString( &TempDomainLogicalName, MAX_RDN_KEY_SIZE );
  3139. BufferLength = MAX_RDN_KEY_SIZE;
  3140. SkipLength = MAX_RDN_KEY_SIZE - GuidLength;
  3141. } else {
  3142. BufferLength = ( TempDomainLogicalName.Length / sizeof( WCHAR ) ) + GuidLength;
  3143. SkipLength = TempDomainLogicalName.Length / sizeof( WCHAR );
  3144. }
  3145. if ( BufferLength >
  3146. ( TempDomainLogicalName.MaximumLength / sizeof( WCHAR ) ) ) {
  3147. //
  3148. // Have to allocate a new buffer
  3149. //
  3150. ScratchBuffer =
  3151. LsapAllocateLsaHeap( ( BufferLength + 1 ) * sizeof( WCHAR ) );
  3152. if ( ScratchBuffer == NULL ) {
  3153. Status = STATUS_INSUFFICIENT_RESOURCES;
  3154. } else {
  3155. RtlCopyMemory( ScratchBuffer,
  3156. TempDomainLogicalName.Buffer,
  3157. TempDomainLogicalName.Length );
  3158. LsapFreeLsaHeap( TempDomainLogicalName.Buffer );
  3159. TempDomainLogicalName.Length = ( USHORT )BufferLength * sizeof( WCHAR );
  3160. TempDomainLogicalName.MaximumLength = TempDomainLogicalName.Length + sizeof( WCHAR );
  3161. TempDomainLogicalName.Buffer = ( PWSTR )ScratchBuffer;
  3162. }
  3163. }
  3164. //
  3165. // Now, build the new string
  3166. //
  3167. if ( NT_SUCCESS( Status ) ) {
  3168. RtlCopyMemory( ( ( PWSTR )TempDomainLogicalName.Buffer + SkipLength ),
  3169. GuidString,
  3170. GuidLength );
  3171. }
  3172. RpcStringFreeW( &GuidString );
  3173. }
  3174. if ( NT_SUCCESS( Status ) && RpcStatus != RPC_S_OK ) {
  3175. Status = STATUS_OBJECT_NAME_INVALID;
  3176. }
  3177. }
  3178. //
  3179. // Try to build the name again. If this fails, such is life...
  3180. //
  3181. if ( NT_SUCCESS( Status ) ) {
  3182. Status = LsapDsGetPhysicalObjectName( ObjectInformation,
  3183. ObjectShouldExist,
  3184. &TempDomainLogicalName,
  3185. PhysicalNameDs );
  3186. }
  3187. }
  3188. }
  3189. Cleanup:
  3190. // Do cleanup that does not depend on success or failure of this function
  3191. //
  3192. LsapFreeLsaHeap( TempDomainLogicalName.Buffer );
  3193. // Do cleanup required on failure of this function
  3194. //
  3195. if ( !NT_SUCCESS( Status ) ) {
  3196. LsapFreeLsaHeap( TempLogicalNameU.Buffer );
  3197. if ( ARGUMENT_PRESENT(LogicalNameU) ) {
  3198. // we dont need to free this since this simply points to TempLogicalNameU
  3199. // which is already freed.
  3200. LogicalNameU->Buffer = NULL;
  3201. }
  3202. if ( ARGUMENT_PRESENT(PhysicalNameU) ) {
  3203. LsapFreeLsaHeap( PhysicalNameU->Buffer );
  3204. PhysicalNameU->Buffer = NULL;
  3205. }
  3206. if ( ARGUMENT_PRESENT(PhysicalNameDs) ) {
  3207. LsapFreeLsaHeap( PhysicalNameDs->Buffer );
  3208. PhysicalNameDs->Buffer = NULL;
  3209. }
  3210. }
  3211. return Status;
  3212. }
  3213. BOOLEAN
  3214. LsapDbIsLocked(
  3215. IN PSAFE_CRITICAL_SECTION CritSect
  3216. )
  3217. /*++
  3218. Routine Description:
  3219. Check if LSA Database is locked.
  3220. Arguments:
  3221. CritSect to check.
  3222. Return Value:
  3223. BOOLEAN - TRUE if LSA database is locked, else false.
  3224. --*/
  3225. {
  3226. return (BOOLEAN)( SafeCritsecLockCount( CritSect ) != -1L);
  3227. }
  3228. BOOLEAN
  3229. LsapDbResourceIsLocked(
  3230. IN PSAFE_RESOURCE Resource
  3231. )
  3232. /*++
  3233. Routine Description:
  3234. Check if LSA Database is locked.
  3235. Arguments:
  3236. CritSect to check.
  3237. Return Value:
  3238. BOOLEAN - TRUE if LSA database is locked, else false.
  3239. --*/
  3240. {
  3241. BOOLEAN IsLocked;
  3242. SafeEnterResourceCritsec( Resource );
  3243. IsLocked = ( SafeNumberOfActive( Resource ) != 0);
  3244. SafeLeaveResourceCritsec( Resource );
  3245. return IsLocked;
  3246. }
  3247. NTSTATUS
  3248. LsarQuerySecurityObject(
  3249. IN LSAPR_HANDLE ObjectHandle,
  3250. IN SECURITY_INFORMATION SecurityInformation,
  3251. OUT PLSAPR_SR_SECURITY_DESCRIPTOR *SecurityDescriptor
  3252. )
  3253. /*++
  3254. Routine Description:
  3255. The LsaQuerySecurityObject API returns security information assigned
  3256. to an LSA Database object.
  3257. Based on the caller's access rights and privileges, this procedure will
  3258. return a security descriptor containing any or all of the object's owner
  3259. ID, group ID, discretionary ACL or system ACL. To read the owner ID,
  3260. group ID, or the discretionary ACL, the caller must be granted
  3261. READ_CONTROL access to the object. To read the system ACL, the caller must
  3262. have SeSecurityPrivilege privilege.
  3263. This API is modelled after the NtQuerySecurityObject() system service.
  3264. Arguments:
  3265. ObjectHandle - A handle to an existing object in the LSA Database.
  3266. SecurityInformation - Supplies a value describing which pieces of
  3267. security information are being queried. The values that may be
  3268. specified are the same as those defined in the NtSetSecurityObject()
  3269. API section.
  3270. SecurityDescriptor - Receives a pointer to a buffer containing the
  3271. requested security information. This information is returned in
  3272. the form of a Self-Relative Security Descriptor.
  3273. Return Values:
  3274. NTSTATUS - Standard Nt Result Code
  3275. STATUS_ACCESS_DENIED - Caller does not have the appropriate access
  3276. to complete the operation.
  3277. STATUS_INVALID_PARAMETER - An invalid parameter has been specified.
  3278. --*/
  3279. {
  3280. NTSTATUS
  3281. Status,
  3282. IgnoreStatus;
  3283. LSAP_DB_HANDLE
  3284. InternalHandle = (LSAP_DB_HANDLE) ObjectHandle;
  3285. ACCESS_MASK
  3286. RequiredAccess = 0;
  3287. BOOLEAN
  3288. Present,
  3289. IgnoreBoolean;
  3290. LSAP_DB_ATTRIBUTE
  3291. Attribute;
  3292. PLSAPR_SR_SECURITY_DESCRIPTOR
  3293. RpcSD = NULL;
  3294. SECURITY_DESCRIPTOR_RELATIVE
  3295. *SD = NULL;
  3296. SECURITY_DESCRIPTOR
  3297. *ReturnSD = NULL;
  3298. ULONG
  3299. ReturnSDLength;
  3300. BOOLEAN ObjectReferenced = FALSE;
  3301. LsarpReturnCheckSetup();
  3302. if (!ARGUMENT_PRESENT( SecurityDescriptor )) {
  3303. return(STATUS_INVALID_PARAMETER);
  3304. }
  3305. //
  3306. // If this is a non-Trusted client, determine the required accesses
  3307. // for querying the object's Security Descriptor. These accesses
  3308. // depend on the information being queried.
  3309. //
  3310. LsapRtlQuerySecurityAccessMask( SecurityInformation, &RequiredAccess );
  3311. //
  3312. // Acquire the Lsa Database lock. Verify that the object handle
  3313. // is a valid handle (of any type) and is trusted or has
  3314. // all of the required accesses granted. Reference the container
  3315. // object handle.
  3316. //
  3317. Status = LsapDbReferenceObject(
  3318. ObjectHandle,
  3319. RequiredAccess,
  3320. InternalHandle->ObjectTypeId,
  3321. InternalHandle->ObjectTypeId,
  3322. LSAP_DB_LOCK
  3323. );
  3324. if ( !NT_SUCCESS( Status ) ) {
  3325. goto Cleanup;
  3326. }
  3327. ObjectReferenced = TRUE;
  3328. //
  3329. // Handle objects in the DS
  3330. //
  3331. if ( LsapDsIsHandleDsHandle( InternalHandle )) {
  3332. //
  3333. // A trusted client needs an SD to replicate to NT 4 BDCs.
  3334. // Give it the default SD for the object.
  3335. //
  3336. if ( InternalHandle->Trusted ) {
  3337. Status = LsapDbCreateSDObject(
  3338. InternalHandle->ContainerHandle,
  3339. ObjectHandle,
  3340. (PSECURITY_DESCRIPTOR*) &SD );
  3341. if ( !NT_SUCCESS( Status ) ) {
  3342. goto Cleanup;
  3343. }
  3344. //
  3345. // Don't support this API for objects in the DS
  3346. // (Otherwise, we'd have to translate the SD to DS format.)
  3347. //
  3348. } else {
  3349. Status = STATUS_NOT_SUPPORTED;
  3350. goto Cleanup;
  3351. }
  3352. //
  3353. // For objects in the registry,
  3354. // read the security descriptor from the registry.
  3355. //
  3356. } else {
  3357. //
  3358. // Read the existing Security Descriptor for the object. This always
  3359. // exists as the value of the SecDesc attribute of the object.
  3360. //
  3361. LsapDbInitializeAttributeDs(
  3362. &Attribute,
  3363. SecDesc,
  3364. NULL,
  3365. 0,
  3366. FALSE
  3367. );
  3368. Status = LsapDbReadAttribute( ObjectHandle, &Attribute );
  3369. if (!NT_SUCCESS(Status)) {
  3370. goto Cleanup;
  3371. }
  3372. SD = Attribute.AttributeValue;
  3373. }
  3374. //
  3375. // ASSERT: SD is the complete security descriptor of the object.
  3376. //
  3377. // Elimate components that weren't requested.
  3378. //
  3379. ASSERT( SD != NULL );
  3380. if ( !(SecurityInformation & OWNER_SECURITY_INFORMATION)) {
  3381. SD->Owner = 0;
  3382. }
  3383. if ( !(SecurityInformation & GROUP_SECURITY_INFORMATION)) {
  3384. SD->Group = 0;
  3385. }
  3386. if ( !(SecurityInformation & DACL_SECURITY_INFORMATION)) {
  3387. SD->Control &= (~SE_DACL_PRESENT);
  3388. }
  3389. if ( !(SecurityInformation & SACL_SECURITY_INFORMATION)) {
  3390. SD->Control &= (~SE_SACL_PRESENT);
  3391. }
  3392. //
  3393. // Now copy the parts of the security descriptor that we are going to return.
  3394. //
  3395. ReturnSDLength = 0;
  3396. ReturnSD = NULL;
  3397. Status = RtlMakeSelfRelativeSD( (PSECURITY_DESCRIPTOR) SD,
  3398. ReturnSD,
  3399. &ReturnSDLength );
  3400. if (Status == STATUS_BUFFER_TOO_SMALL) { // This is the expected case
  3401. ReturnSD = MIDL_user_allocate( ReturnSDLength );
  3402. if (ReturnSD == NULL) {
  3403. Status = STATUS_INSUFFICIENT_RESOURCES;
  3404. goto Cleanup;
  3405. }
  3406. Status = RtlMakeSelfRelativeSD( (PSECURITY_DESCRIPTOR) SD,
  3407. (PSECURITY_DESCRIPTOR) ReturnSD,
  3408. &ReturnSDLength );
  3409. if ( !NT_SUCCESS(Status)) {
  3410. ASSERT( NT_SUCCESS(Status) );
  3411. goto Cleanup;
  3412. }
  3413. } else {
  3414. if ( NT_SUCCESS(Status) ) {
  3415. Status = STATUS_INTERNAL_ERROR;
  3416. }
  3417. goto Cleanup;
  3418. }
  3419. //
  3420. // Allocate the first block of returned memory.
  3421. //
  3422. RpcSD = MIDL_user_allocate( sizeof(LSAPR_SR_SECURITY_DESCRIPTOR) );
  3423. if (RpcSD == NULL) {
  3424. Status = STATUS_INSUFFICIENT_RESOURCES;
  3425. goto Cleanup;
  3426. }
  3427. RpcSD->Length = ReturnSDLength;
  3428. RpcSD->SecurityDescriptor = (PUCHAR)( (PVOID)ReturnSD );
  3429. ReturnSD = NULL;
  3430. Cleanup:
  3431. //
  3432. // free the attribute read from disk
  3433. //
  3434. if ( SD != NULL ) {
  3435. MIDL_user_free( SD );
  3436. }
  3437. if ( ReturnSD != NULL ) {
  3438. MIDL_user_free( ReturnSD );
  3439. }
  3440. if ( ObjectReferenced ) {
  3441. IgnoreStatus = LsapDbDereferenceObject(
  3442. &ObjectHandle,
  3443. InternalHandle->ObjectTypeId,
  3444. InternalHandle->ObjectTypeId,
  3445. LSAP_DB_LOCK,
  3446. (SECURITY_DB_DELTA_TYPE) 0,
  3447. Status
  3448. );
  3449. }
  3450. *SecurityDescriptor = RpcSD;
  3451. LsarpReturnPrologue();
  3452. return(Status);
  3453. }
  3454. NTSTATUS
  3455. LsarSetSecurityObject(
  3456. IN LSAPR_HANDLE ObjectHandle,
  3457. IN SECURITY_INFORMATION SecurityInformation,
  3458. IN PLSAPR_SR_SECURITY_DESCRIPTOR SecurityDescriptor
  3459. )
  3460. /*++
  3461. Routine Description:
  3462. The LsaSetSecurityObject API takes a well formaed Security Descriptor
  3463. and assigns specified portions of it to an object. Based on the flags set
  3464. in the SecurityInformation parameter and the caller's access rights, this
  3465. procedure will replace any or alll of the security information associated
  3466. with the object.
  3467. The caller must have WRITE_OWNER access to the object to change the
  3468. owner or Primary group of the object. The caller must have WRITE_DAC
  3469. access to the object to change the Discretionary ACL. The caller must
  3470. have SeSecurityPrivilege to assign a system ACL to an object.
  3471. This API is modelled after the NtSetSecurityObject() system service.
  3472. Arguments:
  3473. ObjectHandle - A handle to an existing object in the LSA Database.
  3474. SecurityInformation - Indicates which security information is to be
  3475. applied to the object. The values that may be specified are the
  3476. same as those defined in the NtSetSecurityObject() API section.
  3477. The value(s) to be assigned are passed in the SecurityDescriptor
  3478. parameter.
  3479. SecurityDescriptor - A pointer to a well formed Self-Relative
  3480. Security Descriptor.
  3481. Return Values:
  3482. NTSTATUS - Standard Nt Result Code
  3483. STATUS_ACCESS_DENIED - Caller does not have the appropriate access
  3484. to complete the operation.
  3485. STATUS_INVALID_PARAMETER - An invalid parameter has been specified.
  3486. STATUS_INVALID_SECURITY_DESCR - A bad security descriptor was given
  3487. --*/
  3488. {
  3489. NTSTATUS Status;
  3490. NTSTATUS SecondaryStatus = STATUS_SUCCESS;
  3491. ACCESS_MASK RequiredAccess = 0;
  3492. LSAP_DB_HANDLE InternalHandle = (LSAP_DB_HANDLE) ObjectHandle;
  3493. LSAP_DB_ATTRIBUTE Attribute;
  3494. PSECURITY_DESCRIPTOR SetSD = NULL;
  3495. PSECURITY_DESCRIPTOR RetrieveSD = NULL;
  3496. PSECURITY_DESCRIPTOR ModificationSD = NULL;
  3497. ULONG RetrieveSDLength;
  3498. ULONG SetSDLength;
  3499. BOOLEAN ObjectReferenced = FALSE;
  3500. HANDLE ClientToken = NULL;
  3501. LsarpReturnCheckSetup();
  3502. //
  3503. // Verify that a Security Descriptor has been passed.
  3504. //
  3505. if (!ARGUMENT_PRESENT( SecurityDescriptor )) {
  3506. Status = STATUS_INVALID_PARAMETER;
  3507. goto SetSecurityObjectError;
  3508. }
  3509. if (!ARGUMENT_PRESENT( SecurityDescriptor->SecurityDescriptor )) {
  3510. Status = STATUS_INVALID_PARAMETER;
  3511. goto SetSecurityObjectError;
  3512. }
  3513. //
  3514. // Verify its a valid security descriptor
  3515. //
  3516. if ( !RtlValidRelativeSecurityDescriptor(
  3517. (PSECURITY_DESCRIPTOR)SecurityDescriptor->SecurityDescriptor,
  3518. SecurityDescriptor->Length,
  3519. SecurityInformation )) {
  3520. Status = STATUS_INVALID_SECURITY_DESCR;
  3521. goto SetSecurityObjectError;
  3522. }
  3523. ModificationSD = (PSECURITY_DESCRIPTOR)(SecurityDescriptor->SecurityDescriptor);
  3524. //
  3525. // If the caller is non-trusted, figure the accesses required
  3526. // to update the object's Security Descriptor based on the
  3527. // information being changed.
  3528. //
  3529. if (!InternalHandle->Trusted) {
  3530. LsapRtlSetSecurityAccessMask( SecurityInformation, &RequiredAccess);
  3531. }
  3532. //
  3533. // Acquire the Lsa Database lock. Verify that the object handle
  3534. // is a valid handle (of any type), and is trusted or has
  3535. // all of the desired accesses granted. Reference the container
  3536. // object handle.
  3537. //
  3538. Status = LsapDbReferenceObject(
  3539. ObjectHandle,
  3540. RequiredAccess,
  3541. InternalHandle->ObjectTypeId,
  3542. InternalHandle->ObjectTypeId,
  3543. LSAP_DB_LOCK | LSAP_DB_START_TRANSACTION
  3544. );
  3545. if (!NT_SUCCESS(Status)) {
  3546. goto SetSecurityObjectError;
  3547. }
  3548. ObjectReferenced = TRUE;
  3549. //
  3550. // Don't support this API for objects in the DS
  3551. // (Otherwise, we'd have to translate the SD to DS format.)
  3552. //
  3553. if ( LsapDsIsHandleDsHandle( InternalHandle )) {
  3554. Status = STATUS_NOT_SUPPORTED;
  3555. goto SetSecurityObjectError;
  3556. }
  3557. //
  3558. // Read the existing Security Descriptor for the object. This always
  3559. // exists as the value of the SecDesc attribute of the object.
  3560. //
  3561. LsapDbInitializeAttributeDs(
  3562. &Attribute,
  3563. SecDesc,
  3564. NULL,
  3565. 0,
  3566. FALSE
  3567. );
  3568. Status = LsapDbReadAttribute( ObjectHandle, &Attribute );
  3569. if (!NT_SUCCESS(Status)) {
  3570. goto SetSecurityObjectError;
  3571. }
  3572. //
  3573. // Copy the retrieved descriptor into process heap so we can use
  3574. // RTL routines.
  3575. //
  3576. RetrieveSD = Attribute.AttributeValue;
  3577. RetrieveSDLength = Attribute.AttributeValueLength;
  3578. if (RetrieveSD == NULL) {
  3579. Status = STATUS_INTERNAL_DB_CORRUPTION;
  3580. goto SetSecurityObjectError;
  3581. }
  3582. if (RetrieveSDLength == 0) {
  3583. Status = STATUS_INTERNAL_DB_CORRUPTION;
  3584. goto SetSecurityObjectError;
  3585. }
  3586. SetSD = RtlAllocateHeap( RtlProcessHeap(), 0, RetrieveSDLength );
  3587. if (SetSD == NULL) {
  3588. Status = STATUS_INSUFFICIENT_RESOURCES;
  3589. goto SetSecurityObjectError;
  3590. }
  3591. RtlCopyMemory( SetSD, RetrieveSD, RetrieveSDLength );
  3592. //
  3593. // If the caller is replacing the owner, then a handle to the impersonation
  3594. // token is necessary.
  3595. //
  3596. ClientToken = 0;
  3597. if (SecurityInformation & OWNER_SECURITY_INFORMATION) {
  3598. if (!InternalHandle->Trusted) {
  3599. //
  3600. // Client is non-trusted. Impersonate the client and
  3601. // obtain a handle to the impersonation token.
  3602. //
  3603. Status = I_RpcMapWin32Status(RpcImpersonateClient( NULL ));
  3604. if (!NT_SUCCESS(Status)) {
  3605. goto SetSecurityObjectError;
  3606. }
  3607. Status = NtOpenThreadToken(
  3608. NtCurrentThread(),
  3609. TOKEN_QUERY,
  3610. TRUE, //OpenAsSelf
  3611. &ClientToken
  3612. );
  3613. if (!NT_SUCCESS(Status)) {
  3614. if (Status != STATUS_NO_TOKEN) {
  3615. goto SetSecurityObjectError;
  3616. }
  3617. }
  3618. //
  3619. // Stop impersonating the client
  3620. //
  3621. SecondaryStatus = I_RpcMapWin32Status(RpcRevertToSelf());
  3622. if (!NT_SUCCESS(SecondaryStatus)) {
  3623. goto SetSecurityObjectError;
  3624. }
  3625. } else {
  3626. //
  3627. // Client is trusted and so is the LSA Process itself. Open the
  3628. // process token
  3629. //
  3630. Status = NtOpenProcessToken(
  3631. NtCurrentProcess(),
  3632. TOKEN_QUERY,
  3633. &ClientToken
  3634. );
  3635. if (!NT_SUCCESS(Status)) {
  3636. goto SetSecurityObjectError;
  3637. }
  3638. }
  3639. }
  3640. //
  3641. // Build the replacement security descriptor. This must be done in
  3642. // process heap to satisfy the needs of the RTL routine.
  3643. //
  3644. Status = RtlSetSecurityObject(
  3645. SecurityInformation,
  3646. ModificationSD,
  3647. &SetSD,
  3648. &(LsapDbState.
  3649. DbObjectTypes[InternalHandle->ObjectTypeId].GenericMapping),
  3650. ClientToken
  3651. );
  3652. if (!NT_SUCCESS(Status)) {
  3653. goto SetSecurityObjectError;
  3654. }
  3655. SetSDLength = RtlLengthSecurityDescriptor( SetSD );
  3656. //
  3657. // Now replace the existing SD with the updated one.
  3658. //
  3659. Status = LsapDbWriteAttributeObject(
  3660. ObjectHandle,
  3661. &LsapDbNames[SecDesc],
  3662. SetSD,
  3663. SetSDLength
  3664. );
  3665. if (!NT_SUCCESS(Status)) {
  3666. goto SetSecurityObjectError;
  3667. }
  3668. SetSecurityObjectFinish:
  3669. //
  3670. // If necessary, close the Client Token.
  3671. //
  3672. if (ClientToken != 0) {
  3673. SecondaryStatus = NtClose( ClientToken );
  3674. ClientToken = NULL;
  3675. if (!NT_SUCCESS( Status )) {
  3676. goto SetSecurityObjectError;
  3677. }
  3678. }
  3679. //
  3680. // If necessary, free the buffer containing the retrieved SD.
  3681. //
  3682. if (RetrieveSD != NULL) {
  3683. MIDL_user_free( RetrieveSD );
  3684. RetrieveSD = NULL;
  3685. }
  3686. //
  3687. // If necessary, dereference the object, finish the database
  3688. // transaction, notify the LSA Database Replicator of the change,
  3689. // release the LSA Database lock and return.
  3690. //
  3691. if (ObjectReferenced) {
  3692. Status = LsapDbDereferenceObject(
  3693. &ObjectHandle,
  3694. InternalHandle->ObjectTypeId,
  3695. InternalHandle->ObjectTypeId,
  3696. LSAP_DB_LOCK | LSAP_DB_FINISH_TRANSACTION,
  3697. SecurityDbChange,
  3698. Status
  3699. );
  3700. ObjectReferenced = FALSE;
  3701. }
  3702. //
  3703. // Free the Security descriptor that we set
  3704. //
  3705. if ( SetSD ) {
  3706. RtlFreeHeap( RtlProcessHeap(), 0, SetSD );
  3707. }
  3708. LsarpReturnPrologue();
  3709. return(Status);
  3710. SetSecurityObjectError:
  3711. if (NT_SUCCESS(Status)) {
  3712. Status = SecondaryStatus;
  3713. }
  3714. goto SetSecurityObjectFinish;
  3715. }
  3716. NTSTATUS
  3717. LsapDbRebuildCache(
  3718. IN LSAP_DB_OBJECT_TYPE_ID ObjectTypeId
  3719. )
  3720. /*++
  3721. Routine Description:
  3722. This function rebuilds cached information for a given LSA object type.
  3723. Arguments:
  3724. ObjectTypeId - Specifies the Object Type for which the cached information
  3725. is to be rebuilt.
  3726. Return Values:
  3727. NTSTATUS - Standard Nt Result Code
  3728. --*/
  3729. {
  3730. NTSTATUS Status = STATUS_SUCCESS;
  3731. //
  3732. // If caching is not supporte, just return.
  3733. //
  3734. if (!LsapDbIsCacheSupported( ObjectTypeId )) {
  3735. goto RebuildCacheFinish;
  3736. }
  3737. //
  3738. // Call the build routine for the specified LSA object Type
  3739. //
  3740. switch (ObjectTypeId) {
  3741. case PolicyObject:
  3742. SafeAcquireResourceExclusive( &LsapDbState.PolicyCacheLock, TRUE );
  3743. LsapDbMakeCacheInvalid( PolicyObject );
  3744. Status = LsapDbBuildPolicyCache();
  3745. LsapDbMakeCacheValid( PolicyObject );
  3746. SafeReleaseResource( &LsapDbState.PolicyCacheLock );
  3747. break;
  3748. case AccountObject:
  3749. LsapDbMakeCacheInvalid( AccountObject );
  3750. Status = LsapDbBuildAccountCache();
  3751. LsapDbMakeCacheValid( AccountObject );
  3752. break;
  3753. case TrustedDomainObject:
  3754. LsapDbAcquireWriteLockTrustedDomainList();
  3755. LsapDbMakeCacheInvalid( TrustedDomainObject );
  3756. LsapDbPurgeTrustedDomainCache();
  3757. Status = LsapDbBuildTrustedDomainCache();
  3758. LsapDbMakeCacheValid( TrustedDomainObject );
  3759. LsapDbReleaseLockTrustedDomainList();
  3760. break;
  3761. case SecretObject:
  3762. LsapDbMakeCacheInvalid( SecretObject );
  3763. Status = LsapDbBuildSecretCache();
  3764. LsapDbMakeCacheValid( SecretObject );
  3765. break;
  3766. }
  3767. if (!NT_SUCCESS(Status)) {
  3768. goto RebuildCacheError;
  3769. }
  3770. RebuildCacheFinish:
  3771. return(Status);
  3772. RebuildCacheError:
  3773. LsapDbMakeCacheInvalid( ObjectTypeId );
  3774. goto RebuildCacheFinish;
  3775. }