Source code of Windows XP (NT5)
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.

1854 lines
52 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. obse.c
  5. Abstract:
  6. Object Security API calls
  7. Author:
  8. Steve Wood (stevewo) 31-Mar-1989
  9. Revision History:
  10. --*/
  11. #include "obp.h"
  12. #if defined(ALLOC_PRAGMA)
  13. #pragma alloc_text(PAGE,NtSetSecurityObject)
  14. #pragma alloc_text(PAGE,NtQuerySecurityObject)
  15. #pragma alloc_text(PAGE,ObAssignObjectSecurityDescriptor)
  16. #pragma alloc_text(PAGE,ObAssignSecurity)
  17. #pragma alloc_text(PAGE,ObCheckCreateObjectAccess)
  18. #pragma alloc_text(PAGE,ObCheckObjectAccess)
  19. #pragma alloc_text(PAGE,ObpCheckObjectReference)
  20. #pragma alloc_text(PAGE,ObpCheckTraverseAccess)
  21. #pragma alloc_text(PAGE,ObGetObjectSecurity)
  22. #pragma alloc_text(PAGE,ObSetSecurityDescriptorInfo)
  23. #pragma alloc_text(PAGE,ObQuerySecurityDescriptorInfo)
  24. #pragma alloc_text(PAGE,ObReleaseObjectSecurity)
  25. #pragma alloc_text(PAGE,ObValidateSecurityQuota)
  26. #pragma alloc_text(PAGE,ObpValidateAccessMask)
  27. #pragma alloc_text(PAGE,ObSetSecurityObjectByPointer)
  28. #endif
  29. ULONG ObpDefaultSecurityDescriptorLength = 256;
  30. NTSTATUS
  31. NtSetSecurityObject (
  32. IN HANDLE Handle,
  33. IN SECURITY_INFORMATION SecurityInformation,
  34. IN PSECURITY_DESCRIPTOR SecurityDescriptor
  35. )
  36. /*++
  37. Routine Description:
  38. This routine is used to invoke an object's security routine. It
  39. is used to set the object's security state.
  40. Arguments:
  41. Handle - Supplies the handle for the object being modified
  42. SecurityInformation - Indicates the type of information we are
  43. interested in setting. e.g., owner, group, dacl, or sacl.
  44. SecurityDescriptor - Supplies the security descriptor for the
  45. object being modified.
  46. Return Value:
  47. An appropriate NTSTATUS value
  48. --*/
  49. {
  50. NTSTATUS Status;
  51. PVOID Object;
  52. ACCESS_MASK DesiredAccess;
  53. OBJECT_HANDLE_INFORMATION HandleInformation;
  54. KPROCESSOR_MODE RequestorMode;
  55. SECURITY_DESCRIPTOR_RELATIVE *CapturedDescriptor;
  56. PAGED_CODE();
  57. //
  58. // Make sure the passed security descriptor is really there.
  59. // SeCaptureSecurityDescriptor doesn't mind being passed a NULL
  60. // SecurityDescriptor, and will just return NULL back.
  61. //
  62. if (!ARGUMENT_PRESENT( SecurityDescriptor )) {
  63. return( STATUS_ACCESS_VIOLATION );
  64. }
  65. //
  66. // Establish the accesses needed to the object based upon the
  67. // security information being modified.
  68. //
  69. SeSetSecurityAccessMask( SecurityInformation, &DesiredAccess );
  70. Status = ObReferenceObjectByHandle( Handle,
  71. DesiredAccess,
  72. NULL,
  73. RequestorMode = KeGetPreviousMode(),
  74. &Object,
  75. &HandleInformation );
  76. if (NT_SUCCESS( Status )) {
  77. //
  78. // Probe and capture the input security descriptor, and return
  79. // right away if it is ill-formed.
  80. //
  81. // Because the security descriptor is always captured the returned
  82. // security descriptor is in self-relative format.
  83. //
  84. Status = SeCaptureSecurityDescriptor( SecurityDescriptor,
  85. RequestorMode,
  86. PagedPool,
  87. TRUE,
  88. (PSECURITY_DESCRIPTOR *)&CapturedDescriptor );
  89. if (NT_SUCCESS( Status )) {
  90. //
  91. // Now check for a valid combination of what the user wants to set
  92. // and what was supplied in the input security descriptor. If the
  93. // caller wants to set the owner then the owner field of the
  94. // security descriptor better not be null, likewise for the group
  95. // setting. If anything is missing we'll return and error.
  96. //
  97. ASSERT(CapturedDescriptor->Control & SE_SELF_RELATIVE);
  98. if (((SecurityInformation & OWNER_SECURITY_INFORMATION) &&
  99. (CapturedDescriptor->Owner == 0))
  100. ||
  101. ((SecurityInformation & GROUP_SECURITY_INFORMATION) &&
  102. (CapturedDescriptor->Group == 0))) {
  103. SeReleaseSecurityDescriptor( (PSECURITY_DESCRIPTOR)CapturedDescriptor,
  104. RequestorMode,
  105. TRUE );
  106. ObDereferenceObject( Object );
  107. return( STATUS_INVALID_SECURITY_DESCR );
  108. }
  109. Status = ObSetSecurityObjectByPointer( Object,
  110. SecurityInformation,
  111. CapturedDescriptor );
  112. SeReleaseSecurityDescriptor( (PSECURITY_DESCRIPTOR)CapturedDescriptor,
  113. RequestorMode,
  114. TRUE );
  115. }
  116. ObDereferenceObject( Object );
  117. }
  118. return( Status );
  119. }
  120. NTSTATUS
  121. ObSetSecurityObjectByPointer (
  122. IN PVOID Object,
  123. IN SECURITY_INFORMATION SecurityInformation,
  124. IN PSECURITY_DESCRIPTOR SecurityDescriptor
  125. )
  126. /*++
  127. Routine Description:
  128. This routine is used to invoke an object's security routine. It
  129. is used to set the object's security state.
  130. This routine is accessible only to the kernel and assumes that all
  131. necessary validation of parameters has been done by the caller.
  132. Arguments:
  133. Object - Supplies the pointer for the object being modified
  134. SecurityInformation - Indicates the type of information we are
  135. interested in setting. e.g., owner, group, dacl, or sacl.
  136. SecurityDescriptor - Supplies the security descriptor for the
  137. object being modified.
  138. Return Value:
  139. An appropriate NTSTATUS value
  140. --*/
  141. {
  142. NTSTATUS Status;
  143. POBJECT_HEADER ObjectHeader;
  144. POBJECT_TYPE ObjectType;
  145. PAGED_CODE();
  146. // DbgPrint("ObSetSecurityObjectByPointer called for object %#08lx with info "
  147. // "%x and descriptor %#08lx\n",
  148. // Object, SecurityInformation, SecurityDescriptor);
  149. //
  150. // Map the object body to an object header and the corresponding
  151. // object type
  152. //
  153. ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object );
  154. ObjectType = ObjectHeader->Type;
  155. //
  156. // Make sure the passed security descriptor is really there.
  157. //
  158. ASSERT(ARGUMENT_PRESENT( SecurityDescriptor ));
  159. //
  160. // Now invoke the security procedure call back to set the security
  161. // descriptor for the object
  162. //
  163. Status = (ObjectType->TypeInfo.SecurityProcedure)
  164. ( Object,
  165. SetSecurityDescriptor,
  166. &SecurityInformation,
  167. SecurityDescriptor,
  168. NULL,
  169. &ObjectHeader->SecurityDescriptor,
  170. ObjectType->TypeInfo.PoolType,
  171. &ObjectType->TypeInfo.GenericMapping );
  172. // DbgPrint("ObSetSecurityObjectByPointer: object security routine returned "
  173. // "%#08lx\n", Status);
  174. return( Status );
  175. }
  176. NTSTATUS
  177. NtQuerySecurityObject (
  178. IN HANDLE Handle,
  179. IN SECURITY_INFORMATION SecurityInformation,
  180. OUT PSECURITY_DESCRIPTOR SecurityDescriptor,
  181. IN ULONG Length,
  182. OUT PULONG LengthNeeded
  183. )
  184. /*++
  185. Routine Description:
  186. This routine is used to query the security descriptor for an
  187. object.
  188. Arguments:
  189. Handle - Supplies the handle for the object being investigated
  190. SecurityInformation - Indicates the type of information we are
  191. interested in getting. e.g., owner, group, dacl, or sacl.
  192. SecurityDescriptor - Supplies a pointer to where the information
  193. should be returned
  194. Length - Supplies the size, in bytes, of the output buffer
  195. LengthNeeded - Receives the length, in bytes, needed to store
  196. the output security descriptor
  197. Return Value:
  198. An appropriate NTSTATUS value
  199. --*/
  200. {
  201. NTSTATUS Status;
  202. PVOID Object;
  203. ACCESS_MASK DesiredAccess;
  204. OBJECT_HANDLE_INFORMATION HandleInformation;
  205. KPROCESSOR_MODE RequestorMode;
  206. POBJECT_HEADER ObjectHeader;
  207. POBJECT_TYPE ObjectType;
  208. PAGED_CODE();
  209. //
  210. // Probe output parameters
  211. //
  212. RequestorMode = KeGetPreviousMode();
  213. if (RequestorMode != KernelMode) {
  214. try {
  215. ProbeForWriteUlong( LengthNeeded );
  216. ProbeForWrite( SecurityDescriptor, Length, sizeof(ULONG) );
  217. } except(EXCEPTION_EXECUTE_HANDLER) {
  218. return GetExceptionCode();
  219. }
  220. }
  221. //
  222. // Establish the accesses needed to the object based upon the
  223. // security information being queried
  224. //
  225. SeQuerySecurityAccessMask( SecurityInformation, &DesiredAccess );
  226. Status = ObReferenceObjectByHandle( Handle,
  227. DesiredAccess,
  228. NULL,
  229. RequestorMode,
  230. &Object,
  231. &HandleInformation );
  232. if (!NT_SUCCESS( Status )) {
  233. return( Status );
  234. }
  235. //
  236. // Map the object body to an object header and the corresponding
  237. // object type
  238. //
  239. ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object );
  240. ObjectType = ObjectHeader->Type;
  241. //
  242. // Invoke the object type's security callback routine to query
  243. // the object. This routine is assumed to have a try-except around
  244. // the setting of the output security descriptor
  245. //
  246. Status = (ObjectType->TypeInfo.SecurityProcedure)( Object,
  247. QuerySecurityDescriptor,
  248. &SecurityInformation,
  249. SecurityDescriptor,
  250. &Length,
  251. &ObjectHeader->SecurityDescriptor,
  252. ObjectType->TypeInfo.PoolType,
  253. &ObjectType->TypeInfo.GenericMapping );
  254. //
  255. // Indicate the length needed for the security descriptor. This
  256. // will be set even if the callback failed so the caller will know
  257. // the number of bytes necessary
  258. //
  259. try {
  260. *LengthNeeded = Length;
  261. } except(EXCEPTION_EXECUTE_HANDLER) {
  262. ObDereferenceObject( Object );
  263. return(GetExceptionCode());
  264. }
  265. //
  266. // And return to our caller
  267. //
  268. ObDereferenceObject( Object );
  269. return( Status );
  270. }
  271. BOOLEAN
  272. ObCheckObjectAccess (
  273. IN PVOID Object,
  274. IN OUT PACCESS_STATE AccessState,
  275. IN BOOLEAN TypeMutexLocked,
  276. IN KPROCESSOR_MODE AccessMode,
  277. OUT PNTSTATUS AccessStatus
  278. )
  279. /*++
  280. Routine Description:
  281. This routine performs access validation on the passed object. The
  282. remaining desired access mask is extracted from the AccessState
  283. parameter and passes to the appropriate security routine to perform the
  284. access check.
  285. If the access attempt is successful, SeAccessCheck returns a mask
  286. containing the granted accesses. The bits in this mask are turned
  287. on in the PreviouslyGrantedAccess field of the AccessState, and
  288. are turned off in the RemainingDesiredAccess field.
  289. Arguments:
  290. Object - The object being examined.
  291. AccessState - The ACCESS_STATE structure containing accumulated
  292. information about the current attempt to gain access to the object.
  293. TypeMutexLocked - Indicates whether the type mutex for this object's
  294. type is locked. The type mutex is used to protect the object's
  295. security descriptor from being modified while it is being accessed.
  296. AccessMode - The previous processor mode.
  297. AccessStatus - Pointer to a variable to return the status code of the
  298. access attempt. In the case of failure this status code must be
  299. propagated back to the user.
  300. Return Value:
  301. BOOLEAN - TRUE if access is allowed and FALSE otherwise
  302. --*/
  303. {
  304. ACCESS_MASK GrantedAccess = 0;
  305. BOOLEAN AccessAllowed;
  306. BOOLEAN MemoryAllocated;
  307. NTSTATUS Status;
  308. PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
  309. POBJECT_HEADER ObjectHeader;
  310. POBJECT_TYPE ObjectType;
  311. PPRIVILEGE_SET Privileges = NULL;
  312. PAGED_CODE();
  313. //
  314. // Map the object body to an object header and the
  315. // corresponding object type
  316. //
  317. ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object );
  318. ObjectType = ObjectHeader->Type;
  319. //
  320. // Obtain the object's security descriptor
  321. //
  322. Status = ObGetObjectSecurity( Object,
  323. &SecurityDescriptor,
  324. &MemoryAllocated );
  325. //
  326. // If we failed in getting the security descriptor then
  327. // put the object type lock back where it was and return
  328. // the error back to our caller
  329. //
  330. if (!NT_SUCCESS( Status )) {
  331. *AccessStatus = Status;
  332. return( FALSE );
  333. } else {
  334. //
  335. // Otherwise we've been successful at getting the
  336. // object's security descriptor, but now make sure
  337. // it is not null.
  338. if (SecurityDescriptor == NULL) {
  339. *AccessStatus = Status;
  340. return(TRUE);
  341. }
  342. }
  343. //
  344. // We have a non-null security descriptor so now
  345. // lock the caller's tokens until after auditing has been
  346. // performed.
  347. //
  348. SeLockSubjectContext( &AccessState->SubjectSecurityContext );
  349. //
  350. // Do the access check, and if we have some privileges then
  351. // put those in the access state too.
  352. //
  353. AccessAllowed = SeAccessCheck( SecurityDescriptor,
  354. &AccessState->SubjectSecurityContext,
  355. TRUE, // Tokens are locked
  356. AccessState->RemainingDesiredAccess,
  357. AccessState->PreviouslyGrantedAccess,
  358. &Privileges,
  359. &ObjectType->TypeInfo.GenericMapping,
  360. AccessMode,
  361. &GrantedAccess,
  362. AccessStatus );
  363. if (Privileges != NULL) {
  364. Status = SeAppendPrivileges( AccessState,
  365. Privileges );
  366. SeFreePrivileges( Privileges );
  367. }
  368. //
  369. // If we were granted access then set that fact into
  370. // what we've been granted and remove it from what remains
  371. // to be granted.
  372. //
  373. if (AccessAllowed) {
  374. AccessState->PreviouslyGrantedAccess |= GrantedAccess;
  375. AccessState->RemainingDesiredAccess &= ~(GrantedAccess | MAXIMUM_ALLOWED);
  376. }
  377. //
  378. // Audit the attempt to open the object, audit
  379. // the creation of its handle later.
  380. //
  381. if ( SecurityDescriptor != NULL ) {
  382. SeOpenObjectAuditAlarm( &ObjectType->Name,
  383. Object,
  384. NULL, // AbsoluteObjectName
  385. SecurityDescriptor,
  386. AccessState,
  387. FALSE, // ObjectCreated (FALSE, only open here)
  388. AccessAllowed,
  389. AccessMode,
  390. &AccessState->GenerateOnClose );
  391. }
  392. SeUnlockSubjectContext( &AccessState->SubjectSecurityContext );
  393. //
  394. // Free the security descriptor before returning to
  395. // our caller
  396. //
  397. ObReleaseObjectSecurity( SecurityDescriptor,
  398. MemoryAllocated );
  399. return( AccessAllowed );
  400. }
  401. BOOLEAN
  402. ObpCheckObjectReference (
  403. IN PVOID Object,
  404. IN OUT PACCESS_STATE AccessState,
  405. IN BOOLEAN TypeMutexLocked,
  406. IN KPROCESSOR_MODE AccessMode,
  407. OUT PNTSTATUS AccessStatus
  408. )
  409. /*++
  410. Routine Description:
  411. The routine performs access validation on the passed object. The
  412. remaining desired access mask is extracted from the AccessState
  413. parameter and passes to the appropriate security routine to
  414. perform the access check.
  415. If the access attempt is successful, SeAccessCheck returns a mask
  416. containing the granted accesses. The bits in this mask are turned
  417. on in the PreviouslyGrantedAccess field of the AccessState, and
  418. are turned off in the RemainingDesiredAccess field.
  419. This routine differs from ObpCheckObjectAccess in that it calls
  420. a different audit routine.
  421. Arguments:
  422. Object - The object being examined.
  423. AccessState - The ACCESS_STATE structure containing accumulated
  424. information about the current attempt to gain access to the object.
  425. TypeMutexLocked - Indicates whether the type mutex for this object's
  426. type is locked. The type mutex is used to protect the object's
  427. security descriptor from being modified while it is being accessed.
  428. AccessMode - The previous processor mode.
  429. AccessStatus - Pointer to a variable to return the status code of the
  430. access attempt. In the case of failure this status code must be
  431. propagated back to the user.
  432. Return Value:
  433. BOOLEAN - TRUE if access is allowed and FALSE otherwise
  434. --*/
  435. {
  436. BOOLEAN AccessAllowed;
  437. ACCESS_MASK GrantedAccess = 0;
  438. BOOLEAN MemoryAllocated;
  439. PSECURITY_DESCRIPTOR SecurityDescriptor;
  440. NTSTATUS Status;
  441. POBJECT_HEADER ObjectHeader;
  442. POBJECT_TYPE ObjectType;
  443. PPRIVILEGE_SET Privileges = NULL;
  444. PAGED_CODE();
  445. //
  446. // Map the object body to an object header and the
  447. // corresponding object type
  448. //
  449. ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object );
  450. ObjectType = ObjectHeader->Type;
  451. //
  452. // Obtain the object's security descriptor
  453. //
  454. Status = ObGetObjectSecurity( Object,
  455. &SecurityDescriptor,
  456. &MemoryAllocated );
  457. //
  458. // If we failed in getting the security descriptor then
  459. // put the object type lock back where it was and return
  460. // the error back to our caller
  461. //
  462. if (!NT_SUCCESS( Status )) {
  463. *AccessStatus = Status;
  464. return( FALSE );
  465. }
  466. //
  467. // Lock the caller's tokens until after auditing has been
  468. // performed.
  469. //
  470. SeLockSubjectContext( &AccessState->SubjectSecurityContext );
  471. //
  472. // Do the access check, and if we have some privileges then
  473. // put those in the access state too.
  474. //
  475. AccessAllowed = SeAccessCheck( SecurityDescriptor,
  476. &AccessState->SubjectSecurityContext,
  477. TRUE, // Tokens are locked
  478. AccessState->RemainingDesiredAccess,
  479. AccessState->PreviouslyGrantedAccess,
  480. &Privileges,
  481. &ObjectType->TypeInfo.GenericMapping,
  482. AccessMode,
  483. &GrantedAccess,
  484. AccessStatus );
  485. if (AccessAllowed) {
  486. AccessState->PreviouslyGrantedAccess |= GrantedAccess;
  487. AccessState->RemainingDesiredAccess &= ~GrantedAccess;
  488. }
  489. //
  490. // If we have a security descriptor then call the security routine
  491. // to audit this reference and then unlock the caller's token
  492. //
  493. if ( SecurityDescriptor != NULL ) {
  494. SeObjectReferenceAuditAlarm( &AccessState->OperationID,
  495. Object,
  496. SecurityDescriptor,
  497. &AccessState->SubjectSecurityContext,
  498. AccessState->RemainingDesiredAccess | AccessState->PreviouslyGrantedAccess,
  499. ((PAUX_ACCESS_DATA)(AccessState->AuxData))->PrivilegesUsed,
  500. AccessAllowed,
  501. AccessMode );
  502. }
  503. SeUnlockSubjectContext( &AccessState->SubjectSecurityContext );
  504. //
  505. // Finally free the security descriptor
  506. // and return to our caller
  507. //
  508. ObReleaseObjectSecurity( SecurityDescriptor,
  509. MemoryAllocated );
  510. return( AccessAllowed );
  511. }
  512. BOOLEAN
  513. ObpCheckTraverseAccess (
  514. IN PVOID DirectoryObject,
  515. IN ACCESS_MASK TraverseAccess,
  516. IN PACCESS_STATE AccessState OPTIONAL,
  517. IN BOOLEAN TypeMutexLocked,
  518. IN KPROCESSOR_MODE PreviousMode,
  519. OUT PNTSTATUS AccessStatus
  520. )
  521. /*++
  522. Routine Description:
  523. This routine checks for traverse access to the given directory object.
  524. Note that the contents of the AccessState structure are not
  525. modified, since it is assumed that this access check is incidental
  526. to another access operation.
  527. Arguments:
  528. DirectoryObject - The object body of the object being examined.
  529. TraverseAccess - The desired access to the object, most likely DIRECTORY
  530. TRAVERSE access.
  531. AccessState - Checks for traverse access will typically be incidental
  532. to some other access attempt. Information on the current state of
  533. that access attempt is required so that the constituent access
  534. attempts may be associated with each other in the audit log.
  535. This is an OPTIONAL parameter, in which case the call will
  536. success ONLY if the Directory Object grants World traverse
  537. access rights.
  538. TypeMutexLocked - Indicates whether the type mutex for this object's
  539. type is locked. The type mutex is used to protect the object's
  540. security descriptor from being modified while it is being accessed.
  541. PreviousMode - The previous processor mode.
  542. AccessStatus - Pointer to a variable to return the status code of the
  543. access attempt. In the case of failure this status code must be
  544. propagated back to the user.
  545. Return Value:
  546. BOOLEAN - TRUE if access is allowed and FALSE otherwise. AccessStatus
  547. contains the status code to be passed back to the caller. It is not
  548. correct to simply pass back STATUS_ACCESS_DENIED, since this will have
  549. to change with the advent of mandatory access control.
  550. --*/
  551. {
  552. BOOLEAN AccessAllowed;
  553. ACCESS_MASK GrantedAccess = 0;
  554. PSECURITY_DESCRIPTOR SecurityDescriptor;
  555. BOOLEAN MemoryAllocated;
  556. NTSTATUS Status;
  557. POBJECT_HEADER ObjectHeader;
  558. POBJECT_TYPE ObjectType;
  559. PPRIVILEGE_SET Privileges = NULL;
  560. PAGED_CODE();
  561. //
  562. // Map the object body to an object header and corresponding
  563. // object type
  564. //
  565. ObjectHeader = OBJECT_TO_OBJECT_HEADER( DirectoryObject );
  566. ObjectType = ObjectHeader->Type;
  567. //
  568. // Obtain the object's security descriptor and make it was
  569. // successful
  570. //
  571. Status = ObGetObjectSecurity( DirectoryObject,
  572. &SecurityDescriptor,
  573. &MemoryAllocated );
  574. if (!NT_SUCCESS( Status )) {
  575. *AccessStatus = Status;
  576. return( FALSE );
  577. }
  578. //
  579. // Check to see if WORLD has TRAVERSE access, by seeing if the
  580. // token is restricted or the fast traverse check fails meaning
  581. // that the world does not have traverse access
  582. //
  583. if (((AccessState->Flags & TOKEN_IS_RESTRICTED) != 0)
  584. ||
  585. (!SeFastTraverseCheck( SecurityDescriptor,
  586. DIRECTORY_TRAVERSE,
  587. PreviousMode ))) {
  588. //
  589. // SeFastTraverseCheck could be modified to tell us that
  590. // no one has any access to this directory. However,
  591. // we're going to have to fail this entire call if
  592. // that is the case, so we really don't need to worry
  593. // all that much about making it blindingly fast.
  594. //
  595. if (ARGUMENT_PRESENT( AccessState )) {
  596. //
  597. // The world does not have traverse access and we have
  598. // the client's access state so lock down the client's
  599. // token and then do the access check, appending privileges
  600. // if present. The access check will give the answer
  601. // we return back to our caller
  602. //
  603. SeLockSubjectContext( &AccessState->SubjectSecurityContext );
  604. AccessAllowed = SeAccessCheck( SecurityDescriptor,
  605. &AccessState->SubjectSecurityContext,
  606. TRUE, // Tokens are locked
  607. TraverseAccess,
  608. 0,
  609. &Privileges,
  610. &ObjectType->TypeInfo.GenericMapping,
  611. PreviousMode,
  612. &GrantedAccess,
  613. AccessStatus );
  614. if (Privileges != NULL) {
  615. Status = SeAppendPrivileges( AccessState,
  616. Privileges );
  617. SeFreePrivileges( Privileges );
  618. }
  619. //
  620. // If the client's token is locked then now we can unlock it
  621. //
  622. SeUnlockSubjectContext( &AccessState->SubjectSecurityContext );
  623. }
  624. } else {
  625. //
  626. // At this point the world has traverse access
  627. //
  628. AccessAllowed = TRUE;
  629. }
  630. //
  631. // Finally free the security descriptor
  632. // and then return to our caller
  633. //
  634. ObReleaseObjectSecurity( SecurityDescriptor,
  635. MemoryAllocated );
  636. return( AccessAllowed );
  637. }
  638. BOOLEAN
  639. ObCheckCreateObjectAccess (
  640. IN PVOID DirectoryObject,
  641. IN ACCESS_MASK CreateAccess,
  642. IN PACCESS_STATE AccessState,
  643. IN PUNICODE_STRING ComponentName,
  644. IN BOOLEAN TypeMutexLocked,
  645. IN KPROCESSOR_MODE PreviousMode,
  646. OUT PNTSTATUS AccessStatus
  647. )
  648. /*++
  649. Routine Description:
  650. This routine checks to see if we are allowed to create an object in the
  651. given directory, and performs auditing as appropriate.
  652. Arguments:
  653. DirectoryObject - The directory object being examined.
  654. CreateAccess - The access mask corresponding to create access for
  655. this directory type.
  656. AccessState - Checks for traverse access will typically be incidental
  657. to some other access attempt. Information on the current state of
  658. that access attempt is required so that the constituent access
  659. attempts may be associated with each other in the audit log.
  660. ComponentName - Pointer to a Unicode string containing the name of
  661. the object being created.
  662. TypeMutexLocked - Indicates whether the type mutex for this object's
  663. type is locked. The type mutex is used to protect the object's
  664. security descriptor from being modified while it is being accessed.
  665. PreviousMode - The previous processor mode.
  666. AccessStatus - Pointer to a variable to return the status code of the
  667. access attempt. In the case of failure this status code must be
  668. propagated back to the user.
  669. Return Value:
  670. BOOLEAN - TRUE if access is allowed and FALSE otherwise. AccessStatus
  671. contains the status code to be passed back to the caller. It is not
  672. correct to simply pass back STATUS_ACCESS_DENIED, since this will have
  673. to change with the advent of mandatory access control.
  674. --*/
  675. {
  676. BOOLEAN AccessAllowed;
  677. ACCESS_MASK GrantedAccess = 0;
  678. PSECURITY_DESCRIPTOR SecurityDescriptor;
  679. BOOLEAN MemoryAllocated;
  680. NTSTATUS Status;
  681. POBJECT_HEADER ObjectHeader;
  682. POBJECT_TYPE ObjectType;
  683. PPRIVILEGE_SET Privileges = NULL;
  684. BOOLEAN AuditPerformed = FALSE;
  685. PAGED_CODE();
  686. //
  687. // Map the object body to its object header and corresponding
  688. // object type
  689. //
  690. ObjectHeader = OBJECT_TO_OBJECT_HEADER( DirectoryObject );
  691. ObjectType = ObjectHeader->Type;
  692. //
  693. // Obtain the object's security descriptor and make it was
  694. // successful
  695. //
  696. Status = ObGetObjectSecurity( DirectoryObject,
  697. &SecurityDescriptor,
  698. &MemoryAllocated );
  699. if (!NT_SUCCESS( Status )) {
  700. *AccessStatus = Status;
  701. return( FALSE );
  702. }
  703. //
  704. // lock the caller's tokens until after auditing has been
  705. // performed.
  706. //
  707. SeLockSubjectContext( &AccessState->SubjectSecurityContext );
  708. //
  709. // if we have a security descriptor then do an access
  710. // check to see if access is allowed and set in the
  711. // privileges if necessary
  712. //
  713. if (SecurityDescriptor != NULL) {
  714. AccessAllowed = SeAccessCheck( SecurityDescriptor,
  715. &AccessState->SubjectSecurityContext,
  716. TRUE, // Tokens are locked
  717. CreateAccess,
  718. 0,
  719. &Privileges,
  720. &ObjectType->TypeInfo.GenericMapping,
  721. PreviousMode,
  722. &GrantedAccess,
  723. AccessStatus );
  724. if (Privileges != NULL) {
  725. Status = SeAppendPrivileges( AccessState,
  726. Privileges );
  727. SeFreePrivileges( Privileges );
  728. }
  729. //
  730. // This is wrong, but leave for reference.
  731. //
  732. // if (AccessAllowed) {
  733. //
  734. // AccessState->PreviouslyGrantedAccess |= GrantedAccess;
  735. // AccessState->RemainingDesiredAccess &= ~GrantedAccess;
  736. // }
  737. //
  738. } else {
  739. //
  740. // At this point there is not a security descriptor
  741. // so we'll assume access is allowed
  742. //
  743. AccessAllowed = TRUE;
  744. }
  745. //
  746. // Free the caller's token and if the caller didn't have the
  747. // object type locked we need to free it.
  748. //
  749. SeUnlockSubjectContext( &AccessState->SubjectSecurityContext );
  750. //
  751. // Finally free the security descriptor
  752. // and return to our caller
  753. //
  754. ObReleaseObjectSecurity( SecurityDescriptor,
  755. MemoryAllocated );
  756. return( AccessAllowed );
  757. }
  758. NTSTATUS
  759. ObAssignObjectSecurityDescriptor (
  760. IN PVOID Object,
  761. IN PSECURITY_DESCRIPTOR SecurityDescriptor OPTIONAL,
  762. IN POOL_TYPE PoolType // This field is currently ignored.
  763. )
  764. /*++
  765. Routine Description:
  766. Takes a pointer to an object and sets the SecurityDescriptor field
  767. in the object's header.
  768. Arguments:
  769. Object - Supplies a pointer to the object
  770. SecurityDescriptor - Supplies a pointer to the security descriptor
  771. to be assigned to the object. This pointer may be null if there
  772. is no security on the object.
  773. PoolType - Supplies the type of pool memory used to allocate the
  774. security descriptor. This field is currently ignored.
  775. Return Value:
  776. An appropriate NTSTATUS value.
  777. --*/
  778. {
  779. NTSTATUS Status;
  780. PSECURITY_DESCRIPTOR OutputSecurityDescriptor;
  781. POBJECT_HEADER ObjectHeader;
  782. PAGED_CODE();
  783. //
  784. // If the security descriptor isn't supplied then we set the
  785. // object header's security descriptor to null and return
  786. // to our caller
  787. //
  788. ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object );
  789. if (!ARGUMENT_PRESENT(SecurityDescriptor)) {
  790. ExFastRefInitialize ((PEX_FAST_REF) &ObjectHeader->SecurityDescriptor, NULL);
  791. return( STATUS_SUCCESS );
  792. }
  793. //
  794. // Log the new security descriptor into our security database and
  795. // get back the real security descriptor to use
  796. //
  797. Status = ObLogSecurityDescriptor( SecurityDescriptor,
  798. &OutputSecurityDescriptor,
  799. ExFastRefGetAdditionalReferenceCount () + 1 );
  800. //
  801. // If we've been successful so far then set the object's
  802. // security descriptor to the newly allocated one.
  803. //
  804. if (NT_SUCCESS(Status)) {
  805. ExFreePool (SecurityDescriptor);
  806. ASSERT (OutputSecurityDescriptor);
  807. __assume (OutputSecurityDescriptor);
  808. //
  809. // Initialize a fast reference structure with zero additional references
  810. //
  811. ExFastRefInitialize ((PEX_FAST_REF) &ObjectHeader->SecurityDescriptor, OutputSecurityDescriptor);
  812. }
  813. //
  814. // And return to our caller
  815. //
  816. return( Status );
  817. }
  818. NTSTATUS
  819. ObGetObjectSecurity (
  820. IN PVOID Object,
  821. OUT PSECURITY_DESCRIPTOR *SecurityDescriptor,
  822. OUT PBOOLEAN MemoryAllocated
  823. )
  824. /*++
  825. Routine Description:
  826. Given an object, this routine will find its security descriptor.
  827. It will do this by calling the object's security method.
  828. It is possible for an object not to have a security descriptor
  829. at all. Unnamed objects such as events that can only be referenced
  830. by a handle are an example of an object that does not have a
  831. security descriptor.
  832. Arguments:
  833. Object - Supplies the object body being queried.
  834. SecurityDescriptor - Returns a pointer to the object's security
  835. descriptor.
  836. MemoryAllocated - indicates whether we had to allocate pool
  837. memory to hold the security descriptor or not. This should
  838. be passed back into ObReleaseObjectSecurity.
  839. Return Value:
  840. STATUS_SUCCESS - The operation was successful. Note that the
  841. operation may be successful and still return a NULL security
  842. descriptor.
  843. STATUS_INSUFFICIENT_RESOURCES - Insufficient memory was available
  844. to satisfy the request.
  845. --*/
  846. {
  847. SECURITY_INFORMATION SecurityInformation;
  848. ULONG Length = ObpDefaultSecurityDescriptorLength;
  849. NTSTATUS Status;
  850. POBJECT_TYPE ObjectType;
  851. POBJECT_HEADER ObjectHeader;
  852. KIRQL SaveIrql;
  853. PAGED_CODE();
  854. //
  855. // Map the object body to its object header and corresponding
  856. // object type
  857. //
  858. ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object );
  859. ObjectType = ObjectHeader->Type;
  860. //
  861. // If the object is one that uses the default object method,
  862. // its security descriptor is contained in ob's security
  863. // descriptor cache.
  864. //
  865. // Reference it so that it doesn't go away out from under us.
  866. //
  867. if (ObpCentralizedSecurity(ObjectType)) {
  868. *SecurityDescriptor = ObpReferenceSecurityDescriptor( ObjectHeader );
  869. *MemoryAllocated = FALSE;
  870. return( STATUS_SUCCESS );
  871. }
  872. //
  873. // Request a complete security descriptor
  874. //
  875. SecurityInformation = OWNER_SECURITY_INFORMATION |
  876. GROUP_SECURITY_INFORMATION |
  877. DACL_SECURITY_INFORMATION |
  878. SACL_SECURITY_INFORMATION;
  879. //
  880. // We don't know exactly how large is the SD, but we try with the largest
  881. // size we get so far. In general the SD will be released after
  882. // the access is checked. It shouldn't be then a problem of an extra pool usage
  883. // because this oversizing
  884. //
  885. *SecurityDescriptor = ExAllocatePoolWithTag( PagedPool, Length, 'qSbO' );
  886. if (*SecurityDescriptor == NULL) {
  887. return( STATUS_INSUFFICIENT_RESOURCES );
  888. }
  889. *MemoryAllocated = TRUE;
  890. //
  891. // The security method will return an absolute format
  892. // security descriptor that just happens to be in a self
  893. // contained buffer (not to be confused with a self-relative
  894. // security descriptor).
  895. //
  896. ObpBeginTypeSpecificCallOut( SaveIrql );
  897. Status = (*ObjectType->TypeInfo.SecurityProcedure)( Object,
  898. QuerySecurityDescriptor,
  899. &SecurityInformation,
  900. *SecurityDescriptor,
  901. &Length,
  902. &ObjectHeader->SecurityDescriptor,
  903. ObjectType->TypeInfo.PoolType,
  904. &ObjectType->TypeInfo.GenericMapping );
  905. ObpEndTypeSpecificCallOut( SaveIrql, "Security", ObjectType, Object );
  906. if (Status == STATUS_BUFFER_TOO_SMALL) {
  907. //
  908. // The SD is larger than we tried first time. We need to allocate an other
  909. // buffer and try again with this size
  910. //
  911. ExFreePool( *SecurityDescriptor );
  912. *MemoryAllocated = FALSE;
  913. //
  914. // Save the new largest size
  915. //
  916. ObpDefaultSecurityDescriptorLength = Length;
  917. // DbgPrint( "ObpDefaultSecurityDescriptorLength increased to %ld\n",
  918. // ObpDefaultSecurityDescriptorLength);
  919. //
  920. // Now that we know how large the security descriptor is we
  921. // can allocate space for it
  922. //
  923. *SecurityDescriptor = ExAllocatePoolWithTag( PagedPool, Length, 'qSbO' );
  924. if (*SecurityDescriptor == NULL) {
  925. return( STATUS_INSUFFICIENT_RESOURCES );
  926. }
  927. *MemoryAllocated = TRUE;
  928. //
  929. // The security method will return an absolute format
  930. // security descriptor that just happens to be in a self
  931. // contained buffer (not to be confused with a self-relative
  932. // security descriptor).
  933. //
  934. ObpBeginTypeSpecificCallOut( SaveIrql );
  935. Status = (*ObjectType->TypeInfo.SecurityProcedure)( Object,
  936. QuerySecurityDescriptor,
  937. &SecurityInformation,
  938. *SecurityDescriptor,
  939. &Length,
  940. &ObjectHeader->SecurityDescriptor,
  941. ObjectType->TypeInfo.PoolType,
  942. &ObjectType->TypeInfo.GenericMapping );
  943. ObpEndTypeSpecificCallOut( SaveIrql, "Security", ObjectType, Object );
  944. }
  945. if (!NT_SUCCESS( Status )) {
  946. ExFreePool( *SecurityDescriptor );
  947. *MemoryAllocated = FALSE;
  948. }
  949. return( Status );
  950. }
  951. VOID
  952. ObReleaseObjectSecurity (
  953. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  954. IN BOOLEAN MemoryAllocated
  955. )
  956. /*++
  957. Routine Description:
  958. This function will free up any memory associated with a queried
  959. security descriptor. This undoes the function ObGetObjectSecurity
  960. Arguments:
  961. SecurityDescriptor - Supplies a pointer to the security descriptor
  962. to be freed.
  963. MemoryAllocated - Supplies whether or not we should free the
  964. memory pointed to by SecurityDescriptor.
  965. Return Value:
  966. None.
  967. --*/
  968. {
  969. PAGED_CODE();
  970. //
  971. // Check if there is a security descriptor to actually free
  972. //
  973. if ( SecurityDescriptor != NULL ) {
  974. //
  975. // If ObGetObjectSecurity allocated memory then we
  976. // need to free it. Otherwise what the earlier routine did
  977. // was reference the object to keep the security descriptor
  978. // to keep it from going away
  979. //
  980. if (MemoryAllocated) {
  981. ExFreePool( SecurityDescriptor );
  982. } else {
  983. ObDereferenceSecurityDescriptor( SecurityDescriptor, 1);
  984. }
  985. }
  986. }
  987. NTSTATUS
  988. ObValidateSecurityQuota (
  989. IN PVOID Object,
  990. IN ULONG NewSize
  991. )
  992. /*++
  993. Routine Description:
  994. This routine will check to see if the new security information
  995. is larger than is allowed by the object's pre-allocated quota.
  996. Arguments:
  997. Object - Supplies a pointer to the object whose information is to be
  998. modified.
  999. NewSize - Supplies the size of the proposed new security
  1000. information.
  1001. Return Value:
  1002. STATUS_SUCCESS - New size is within alloted quota.
  1003. STATUS_QUOTA_EXCEEDED - The desired adjustment would have exceeded
  1004. the permitted security quota for this object.
  1005. --*/
  1006. {
  1007. POBJECT_HEADER ObjectHeader;
  1008. POBJECT_HEADER_QUOTA_INFO QuotaInfo;
  1009. PAGED_CODE();
  1010. //
  1011. // Map the object body to its object header and corresponding
  1012. // quota information block
  1013. //
  1014. ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object );
  1015. //
  1016. // If we never charged quota originaly then don't worry about it now.
  1017. //
  1018. if (ObjectHeader->QuotaBlockCharged == (PEPROCESS_QUOTA_BLOCK) 1) {
  1019. return( STATUS_SUCCESS );
  1020. }
  1021. QuotaInfo = OBJECT_HEADER_TO_QUOTA_INFO( ObjectHeader );
  1022. //
  1023. // If there isn't any quota info and the new size is greater
  1024. // then the default security quota then if the object uses
  1025. // the default value then we've exceeded quota otherwise
  1026. // let the caller get the quota
  1027. //
  1028. if ((QuotaInfo == NULL) && (NewSize > SE_DEFAULT_SECURITY_QUOTA)) {
  1029. if (!(ObjectHeader->Flags & OB_FLAG_DEFAULT_SECURITY_QUOTA)) {
  1030. return( STATUS_SUCCESS );
  1031. }
  1032. return( STATUS_QUOTA_EXCEEDED );
  1033. //
  1034. // If the quota is not null and the new size is greater than the
  1035. // allowed quota charge then if the charge is zero we grant the
  1036. // request otherwise we've exceeded quota.
  1037. //
  1038. } else if ((QuotaInfo != NULL) && (NewSize > QuotaInfo->SecurityDescriptorCharge)) {
  1039. if (QuotaInfo->SecurityDescriptorCharge == 0) {
  1040. //
  1041. // Should really charge quota here.
  1042. //
  1043. // QuotaInfo->SecurityDescriptorCharge = SeComputeSecurityQuota( NewSize );
  1044. return( STATUS_SUCCESS );
  1045. }
  1046. return( STATUS_QUOTA_EXCEEDED );
  1047. //
  1048. // Otherwise we have two cases. (1) there isn't any quota info but
  1049. // the size is within limits or (2) there is a quota info block and
  1050. // the size is within the specified security descriptor charge so
  1051. // return success to our caller
  1052. //
  1053. } else {
  1054. return( STATUS_SUCCESS );
  1055. }
  1056. }
  1057. NTSTATUS
  1058. ObAssignSecurity (
  1059. IN PACCESS_STATE AccessState,
  1060. IN PSECURITY_DESCRIPTOR ParentDescriptor OPTIONAL,
  1061. IN PVOID Object,
  1062. IN POBJECT_TYPE ObjectType
  1063. )
  1064. /*++
  1065. Routine Description:
  1066. This routine will assign a security descriptor to a newly created object.
  1067. It assumes that the AccessState parameter contains a captured security
  1068. descriptor.
  1069. Arguments:
  1070. AccessState - The AccessState containing the security information
  1071. for this object creation.
  1072. ParentDescriptor - The security descriptor from the parent object, if
  1073. available.
  1074. Object - A pointer to the object being created.
  1075. ObjectType - Supplies the type of object being created.
  1076. Return Value:
  1077. STATUS_SUCCESS - indicates the operation was successful.
  1078. STATUS_INVALID_OWNER - The owner SID provided as the owner of the
  1079. target security descriptor is not one the caller is authorized
  1080. to assign as the owner of an object.
  1081. STATUS_PRIVILEGE_NOT_HELD - The caller does not have the privilege
  1082. necessary to explicitly assign the specified system ACL.
  1083. SeSecurityPrivilege privilege is needed to explicitly assign
  1084. system ACLs to objects.
  1085. --*/
  1086. {
  1087. PSECURITY_DESCRIPTOR NewDescriptor = NULL;
  1088. NTSTATUS Status;
  1089. KIRQL SaveIrql;
  1090. PAGED_CODE();
  1091. //
  1092. // SeAssignSecurity will construct the final version
  1093. // of the security descriptor
  1094. //
  1095. Status = SeAssignSecurity( ParentDescriptor,
  1096. AccessState->SecurityDescriptor,
  1097. &NewDescriptor,
  1098. (BOOLEAN)(ObjectType == ObpDirectoryObjectType),
  1099. &AccessState->SubjectSecurityContext,
  1100. &ObjectType->TypeInfo.GenericMapping,
  1101. PagedPool );
  1102. if (!NT_SUCCESS( Status )) {
  1103. return( Status );
  1104. }
  1105. ObpBeginTypeSpecificCallOut( SaveIrql );
  1106. //
  1107. // Now invoke the security method callback to finish
  1108. // the assignment.
  1109. //
  1110. Status = (*ObjectType->TypeInfo.SecurityProcedure)( Object,
  1111. AssignSecurityDescriptor,
  1112. NULL,
  1113. NewDescriptor,
  1114. NULL,
  1115. NULL,
  1116. PagedPool,
  1117. &ObjectType->TypeInfo.GenericMapping );
  1118. ObpEndTypeSpecificCallOut( SaveIrql, "Security", ObjectType, Object );
  1119. if (!NT_SUCCESS( Status )) {
  1120. //
  1121. // The attempt to assign the security descriptor to the object
  1122. // failed. Free the space used by the new security descriptor.
  1123. //
  1124. SeDeassignSecurity( &NewDescriptor );
  1125. }
  1126. //
  1127. // And return to our caller
  1128. //
  1129. return( Status );
  1130. }
  1131. NTSTATUS
  1132. ObQuerySecurityDescriptorInfo(
  1133. IN PVOID Object,
  1134. IN PSECURITY_INFORMATION SecurityInformation,
  1135. OUT PSECURITY_DESCRIPTOR SecurityDescriptor,
  1136. IN OUT PULONG Length,
  1137. IN PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor
  1138. )
  1139. /*++
  1140. Routine Description:
  1141. This routine will extract the desired information from the
  1142. passed security descriptor and return the information in
  1143. the passed buffer as a security descriptor in self-relative
  1144. format.
  1145. This routine assumes that all parameters are captured and
  1146. safe to reference.
  1147. Arguments:
  1148. Object - Object that is having its security queried
  1149. SecurityInformation - Specifies what information is being queried.
  1150. SecurityDescriptor - Supplies the buffer to output the requested
  1151. information into.
  1152. This buffer has been probed only to the size indicated by
  1153. the Length parameter. Since it still points into user space,
  1154. it must always be accessed in a try clause.
  1155. Length - Supplies the address of a variable containing the length of
  1156. the security descriptor buffer. Upon return this variable will
  1157. contain the length needed to store the requested information.
  1158. ObjectsSecurityDescriptor - Supplies the address of a pointer to
  1159. the objects security descriptor. The passed security descriptor
  1160. must be in self-relative format.
  1161. Return Value:
  1162. NTSTATUS - STATUS_SUCCESS if successful and an appropriate error value
  1163. otherwise
  1164. --*/
  1165. {
  1166. NTSTATUS Status;
  1167. POBJECT_HEADER ObjectHeader;
  1168. PSECURITY_DESCRIPTOR ReferencedSecurityDescriptor;
  1169. PAGED_CODE();
  1170. ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object );
  1171. //
  1172. // Reference the security descriptor
  1173. //
  1174. ReferencedSecurityDescriptor = ObpReferenceSecurityDescriptor( ObjectHeader );
  1175. Status = SeQuerySecurityDescriptorInfo( SecurityInformation,
  1176. SecurityDescriptor,
  1177. Length,
  1178. &ReferencedSecurityDescriptor
  1179. );
  1180. if (ReferencedSecurityDescriptor != NULL) {
  1181. ObDereferenceSecurityDescriptor ( ReferencedSecurityDescriptor, 1 );
  1182. }
  1183. return( Status );
  1184. }
  1185. NTSTATUS
  1186. ObSetSecurityDescriptorInfo (
  1187. IN PVOID Object,
  1188. IN PSECURITY_INFORMATION SecurityInformation,
  1189. IN OUT PSECURITY_DESCRIPTOR SecurityDescriptor,
  1190. IN OUT PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor,
  1191. IN POOL_TYPE PoolType,
  1192. IN PGENERIC_MAPPING GenericMapping
  1193. )
  1194. /*++
  1195. Routine Description:
  1196. Sets the security descriptor on an already secure object.
  1197. Arguments:
  1198. Object - Pointer to the object being modified.
  1199. SecurityInformation - Describes which information in the SecurityDescriptor parameter
  1200. is relevent.
  1201. SecurityDescriptor - Provides the new security information.
  1202. ObjectsSecurityDescriptor - Provides/returns the object's security descriptor.
  1203. PoolType - The pool the ObjectSecurityDescriptor is allocated from.
  1204. GenericMapping - Supplies the generic mapping for the object.
  1205. Return Value:
  1206. An appropriate status value
  1207. --*/
  1208. {
  1209. PSECURITY_DESCRIPTOR OldDescriptor;
  1210. PSECURITY_DESCRIPTOR NewDescriptor;
  1211. PSECURITY_DESCRIPTOR CachedDescriptor;
  1212. NTSTATUS Status;
  1213. POBJECT_HEADER ObjectHeader;
  1214. EX_FAST_REF OldRef;
  1215. PAGED_CODE();
  1216. //
  1217. // Check the rest of our input and call the default set security
  1218. // method. Also make sure no one is modifying the security descriptor
  1219. // while we're looking at it.
  1220. //
  1221. ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object );
  1222. //
  1223. // In order to preserve some protected fields in the SD (like the SACL) we need to make sure that only one
  1224. // thread updates it at any one time. If we didn't do this another modification could wipe out a SACL
  1225. // an administrator was adding.
  1226. //
  1227. while (1) {
  1228. //
  1229. // Reference the security descriptor
  1230. //
  1231. OldDescriptor = ObpReferenceSecurityDescriptor( ObjectHeader );
  1232. NewDescriptor = OldDescriptor;
  1233. Status = SeSetSecurityDescriptorInfo( Object,
  1234. SecurityInformation,
  1235. SecurityDescriptor,
  1236. &NewDescriptor,
  1237. PoolType,
  1238. GenericMapping );
  1239. //
  1240. // If we successfully set the new security descriptor then we
  1241. // need to log it in our database and get yet another pointer
  1242. // to the finaly security descriptor
  1243. //
  1244. if ( NT_SUCCESS( Status )) {
  1245. Status = ObLogSecurityDescriptor( NewDescriptor,
  1246. &CachedDescriptor,
  1247. ExFastRefGetAdditionalReferenceCount () + 1 );
  1248. ExFreePool( NewDescriptor );
  1249. if ( NT_SUCCESS( Status )) {
  1250. //
  1251. // Now we need to see if anyone else update this security descriptor inside the
  1252. // gap where we didn't hold the lock. If they did then we just try it all again.
  1253. //
  1254. OldRef = ExFastRefCompareSwapObject ((PEX_FAST_REF)ObjectsSecurityDescriptor,
  1255. CachedDescriptor,
  1256. OldDescriptor);
  1257. if (ExFastRefEqualObjects (OldRef, OldDescriptor)) {
  1258. //
  1259. // The swap occured ok. We must now flush any slow refers out of the slow ref path before
  1260. // dereferencing the object. We do this by obtaining and dropping the object lock.
  1261. //
  1262. ObpLockObject( ObjectHeader );
  1263. ObpUnlockObject( ObjectHeader );
  1264. //
  1265. // If there was an original object then we need to work out how many
  1266. // cached references there were (if any) and return them.
  1267. //
  1268. ObDereferenceSecurityDescriptor( OldDescriptor, ExFastRefGetUnusedReferences (OldRef) + 2 );
  1269. break;
  1270. } else {
  1271. ObDereferenceSecurityDescriptor( OldDescriptor, 1 );
  1272. ObDereferenceSecurityDescriptor( CachedDescriptor, ExFastRefGetAdditionalReferenceCount () + 1);
  1273. }
  1274. } else {
  1275. //
  1276. // Dereference old SecurityDescriptor
  1277. //
  1278. ObDereferenceSecurityDescriptor( OldDescriptor, 1 );
  1279. break;
  1280. }
  1281. } else {
  1282. //
  1283. // Dereference old SecurityDescriptor
  1284. //
  1285. if (OldDescriptor != NULL) {
  1286. ObDereferenceSecurityDescriptor( OldDescriptor, 1 );
  1287. }
  1288. break;
  1289. }
  1290. }
  1291. //
  1292. // And return to our caller
  1293. //
  1294. return( Status );
  1295. }
  1296. NTSTATUS
  1297. ObpValidateAccessMask (
  1298. PACCESS_STATE AccessState
  1299. )
  1300. /*++
  1301. Routine Description:
  1302. Checks the desired access mask of a passed object against the
  1303. passed security descriptor.
  1304. Arguments:
  1305. AccessState - A pointer to the AccessState for the pending operation.
  1306. Return Value:
  1307. Only returns STATUS_SUCCESS
  1308. --*/
  1309. {
  1310. SECURITY_DESCRIPTOR *SecurityDescriptor = AccessState->SecurityDescriptor;
  1311. PAGED_CODE();
  1312. //
  1313. // First make sure the access state has a security descriptor. If there
  1314. // is one and it has a system acl and the previously granted access did
  1315. // not include system security then add the fact that we want system
  1316. // security to the remaining desired access state.
  1317. //
  1318. if (SecurityDescriptor != NULL) {
  1319. if ( SecurityDescriptor->Control & SE_SACL_PRESENT ) {
  1320. if ( !(AccessState->PreviouslyGrantedAccess & ACCESS_SYSTEM_SECURITY)) {
  1321. AccessState->RemainingDesiredAccess |= ACCESS_SYSTEM_SECURITY;
  1322. }
  1323. }
  1324. }
  1325. return( STATUS_SUCCESS );
  1326. }