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.

5298 lines
159 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. SecurSup.c
  5. Abstract:
  6. This module implements the Ntfs Security Support routines
  7. Author:
  8. Gary Kimura [GaryKi] 27-Dec-1991
  9. Revision History:
  10. --*/
  11. #include "NtfsProc.h"
  12. #define Dbg (DEBUG_TRACE_SECURSUP)
  13. #define DbgAcl (DEBUG_TRACE_SECURSUP | DEBUG_TRACE_ACLINDEX)
  14. //
  15. // Define a tag for general pool allocations from this module
  16. //
  17. #undef MODULE_POOL_TAG
  18. #define MODULE_POOL_TAG ('SFtN')
  19. UNICODE_STRING FileString = CONSTANT_UNICODE_STRING( L"File" );
  20. //
  21. // Local procedure prototypes
  22. //
  23. PSHARED_SECURITY
  24. NtfsCacheSharedSecurityByDescriptor (
  25. IN PIRP_CONTEXT IrpContext,
  26. PSECURITY_DESCRIPTOR SecurityDescriptor,
  27. ULONG SecurityDescriptorLength,
  28. IN BOOLEAN RaiseIfInvalid
  29. );
  30. VOID
  31. NtfsStoreSecurityDescriptor (
  32. PIRP_CONTEXT IrpContext,
  33. IN PFCB Fcb,
  34. IN BOOLEAN LogIt
  35. );
  36. PSHARED_SECURITY
  37. FindCachedSharedSecurityByHashUnsafe (
  38. IN PVCB Vcb,
  39. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  40. IN ULONG SecurityDescriptorLength,
  41. IN ULONG Hash
  42. );
  43. VOID
  44. AddCachedSharedSecurityUnsafe (
  45. IN PVCB Vcb,
  46. PSHARED_SECURITY SharedSecurity
  47. );
  48. BOOLEAN
  49. MapSecurityIdToSecurityDescriptorHeaderUnsafe (
  50. IN PIRP_CONTEXT IrpContext,
  51. IN PVCB Vcb,
  52. IN SECURITY_ID SecurityId,
  53. OUT PSECURITY_DESCRIPTOR_HEADER *SecurityDescriptorHeader,
  54. OUT PBCB *Bcb
  55. );
  56. NTSTATUS
  57. NtOfsMatchSecurityHash (
  58. IN PINDEX_ROW IndexRow,
  59. IN OUT PVOID MatchData
  60. );
  61. VOID
  62. NtOfsLookupSecurityDescriptorInIndex (
  63. PIRP_CONTEXT IrpContext,
  64. IN OUT PSHARED_SECURITY SharedSecurity
  65. );
  66. PSHARED_SECURITY
  67. GetSharedSecurityFromDescriptorUnsafe (
  68. IN PIRP_CONTEXT IrpContext,
  69. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  70. IN ULONG SecurityDescriptorLength,
  71. IN BOOLEAN RaiseIfInvalid
  72. );
  73. #ifdef NTFS_CACHE_RIGHTS
  74. //
  75. // Local procedure prototypes for access rights cache
  76. //
  77. VOID
  78. NtfsAddCachedRights (
  79. IN PVCB Vcb,
  80. IN PSHARED_SECURITY SharedSecurity,
  81. IN ACCESS_MASK Rights,
  82. IN PLUID TokenId,
  83. IN PLUID ModifiedId
  84. );
  85. INLINE ACCESS_MASK
  86. NtfsGetCachedRightsWorld (
  87. IN PCACHED_ACCESS_RIGHTS CachedRights
  88. )
  89. {
  90. return CachedRights->EveryoneRights;
  91. }
  92. INLINE VOID
  93. NtfsSetCachedRightsWorld (
  94. IN PSHARED_SECURITY SharedSecurity
  95. )
  96. {
  97. SeGetWorldRights( &SharedSecurity->SecurityDescriptor,
  98. IoGetFileObjectGenericMapping(),
  99. &SharedSecurity->CachedRights.EveryoneRights );
  100. //
  101. // Make certain that MAXIMUM_ALLOWED is not in the rights.
  102. //
  103. ClearFlag( SharedSecurity->CachedRights.EveryoneRights, MAXIMUM_ALLOWED );
  104. return;
  105. }
  106. #endif
  107. #if (DBG || defined( NTFS_FREE_ASSERTS ))
  108. VOID
  109. NtfsVerifySecurity (
  110. PIRP_CONTEXT IrpContext,
  111. PVCB Vcb
  112. );
  113. #endif
  114. #ifdef ALLOC_PRAGMA
  115. #pragma alloc_text(PAGE, NtfsAssignSecurity)
  116. #pragma alloc_text(PAGE, NtfsCacheSharedSecurityByDescriptor)
  117. #pragma alloc_text(PAGE, NtfsModifySecurity)
  118. #pragma alloc_text(PAGE, NtfsQuerySecurity)
  119. #pragma alloc_text(PAGE, NtfsAccessCheck)
  120. #pragma alloc_text(PAGE, NtfsCheckFileForDelete)
  121. #pragma alloc_text(PAGE, NtfsCheckIndexForAddOrDelete)
  122. #pragma alloc_text(PAGE, GetSharedSecurityFromDescriptorUnsafe)
  123. #pragma alloc_text(PAGE, NtfsSetFcbSecurityFromDescriptor)
  124. #pragma alloc_text(PAGE, NtfsNotifyTraverseCheck)
  125. #pragma alloc_text(PAGE, NtfsInitializeSecurity)
  126. #pragma alloc_text(PAGE, NtfsCacheSharedSecurityBySecurityId)
  127. #pragma alloc_text(PAGE, FindCachedSharedSecurityByHashUnsafe)
  128. #pragma alloc_text(PAGE, AddCachedSharedSecurityUnsafe)
  129. #pragma alloc_text(PAGE, NtOfsPurgeSecurityCache)
  130. #pragma alloc_text(PAGE, MapSecurityIdToSecurityDescriptorHeaderUnsafe)
  131. #pragma alloc_text(PAGE, NtfsLoadSecurityDescriptor)
  132. #pragma alloc_text(PAGE, NtOfsMatchSecurityHash)
  133. #pragma alloc_text(PAGE, NtOfsLookupSecurityDescriptorInIndex)
  134. #pragma alloc_text(PAGE, GetSecurityIdFromSecurityDescriptorUnsafe)
  135. #pragma alloc_text(PAGE, NtfsStoreSecurityDescriptor)
  136. #pragma alloc_text(PAGE, NtfsCacheSharedSecurityForCreate)
  137. #pragma alloc_text(PAGE, NtOfsCollateSecurityHash)
  138. #pragma alloc_text(PAGE, NtfsCanAdministerVolume)
  139. #endif
  140. #ifdef NTFS_CACHE_RIGHTS
  141. #ifdef ALLOC_PRAGMA
  142. #pragma alloc_text(PAGE, NtfsGetCachedRightsById)
  143. #pragma alloc_text(PAGE, NtfsGetCachedRights)
  144. #pragma alloc_text(PAGE, NtfsAddCachedRights)
  145. #endif
  146. #endif
  147. VOID
  148. NtfsAssignSecurity (
  149. IN PIRP_CONTEXT IrpContext,
  150. IN PFCB ParentFcb,
  151. IN PIRP Irp,
  152. IN PFCB NewFcb,
  153. IN PFILE_RECORD_SEGMENT_HEADER FileRecord,
  154. IN PBCB FileRecordBcb,
  155. IN LONGLONG FileOffset,
  156. IN OUT PBOOLEAN LogIt
  157. )
  158. /*++
  159. Routine Description:
  160. LEGACY NOTE - this routine disappears when all volumes go to Cairo.
  161. This routine constructs and assigns a new security descriptor to the
  162. specified file/directory. The new security descriptor is placed both
  163. on the fcb and on the disk.
  164. This will only be called in the context of an open/create operation.
  165. It currently MUST NOT be called to store a security descriptor for
  166. an existing file, because it instructs NtfsStoreSecurityDescriptor
  167. to not log the change.
  168. If this is a large security descriptor then it is possible that
  169. AllocateClusters may be called twice within the call to AddAllocation
  170. when the attribute is created. If so then the second call will always
  171. log the changes. In that case we need to log all of the operations to
  172. create this security attribute and also we must log the current state
  173. of the file record.
  174. It is possible that our caller has already started logging operations against
  175. this log record. In that case we always log the security changes.
  176. Arguments:
  177. ParentFcb - Supplies the directory under which the new fcb exists
  178. Irp - Supplies the Irp being processed
  179. NewFcb - Supplies the fcb that is being assigned a new security descriptor
  180. FileRecord - Supplies the file record for this operation. Used if we
  181. have to log against the file record.
  182. FileRecordBcb - Bcb for the file record above.
  183. FileOffset - File offset in the Mft for this file record.
  184. LogIt - On entry this indicates whether our caller wants this operation
  185. logged. On exit we return TRUE if we logged the security change.
  186. Return Value:
  187. None.
  188. --*/
  189. {
  190. PSECURITY_DESCRIPTOR SecurityDescriptor;
  191. NTSTATUS Status;
  192. BOOLEAN IsDirectory;
  193. PACCESS_STATE AccessState;
  194. PIO_STACK_LOCATION IrpSp;
  195. ULONG SecurityDescLength;
  196. ASSERT_IRP_CONTEXT( IrpContext );
  197. ASSERT_FCB( ParentFcb );
  198. ASSERT_IRP( Irp );
  199. ASSERT_FCB( NewFcb );
  200. PAGED_CODE();
  201. if (NewFcb->Vcb->SecurityDescriptorStream != NULL) {
  202. return;
  203. }
  204. DebugTrace( +1, Dbg, ("NtfsAssignSecurity...\n") );
  205. //
  206. // First decide if we are creating a file or a directory
  207. //
  208. IrpSp = IoGetCurrentIrpStackLocation(Irp);
  209. if (FlagOn(IrpSp->Parameters.Create.Options, FILE_DIRECTORY_FILE)) {
  210. IsDirectory = TRUE;
  211. } else {
  212. IsDirectory = FALSE;
  213. }
  214. //
  215. // Extract the parts of the Irp that we need to do our assignment
  216. //
  217. AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState;
  218. //
  219. // Check if we need to load the security descriptor for the parent.
  220. //
  221. if (ParentFcb->SharedSecurity == NULL) {
  222. NtfsLoadSecurityDescriptor( IrpContext, ParentFcb );
  223. }
  224. ASSERT( ParentFcb->SharedSecurity != NULL );
  225. //
  226. // Create a new security descriptor for the file and raise if there is
  227. // an error
  228. //
  229. if (!NT_SUCCESS( Status = SeAssignSecurity( &ParentFcb->SharedSecurity->SecurityDescriptor,
  230. AccessState->SecurityDescriptor,
  231. &SecurityDescriptor,
  232. IsDirectory,
  233. &AccessState->SubjectSecurityContext,
  234. IoGetFileObjectGenericMapping(),
  235. PagedPool ))) {
  236. NtfsRaiseStatus( IrpContext, Status, NULL, NULL );
  237. }
  238. //
  239. // Load the security descriptor into the Fcb
  240. //
  241. SecurityDescLength = RtlLengthSecurityDescriptor( SecurityDescriptor );
  242. try {
  243. //
  244. // Make sure the length is non-zero.
  245. //
  246. if (SecurityDescLength == 0) {
  247. NtfsRaiseStatus( IrpContext, STATUS_INVALID_PARAMETER, NULL, NULL );
  248. }
  249. ASSERT( SeValidSecurityDescriptor( SecurityDescLength, SecurityDescriptor ));
  250. NtfsSetFcbSecurityFromDescriptor(
  251. IrpContext,
  252. NewFcb,
  253. SecurityDescriptor,
  254. SecurityDescLength,
  255. TRUE );
  256. } finally {
  257. //
  258. // Free the security descriptor created by Se
  259. //
  260. SeDeassignSecurity( &SecurityDescriptor );
  261. }
  262. //
  263. // If the security descriptor is large enough that it may cause us to
  264. // start logging in the StoreSecurity call below then make sure everything
  265. // is logged.
  266. //
  267. if (!(*LogIt) &&
  268. (SecurityDescLength > BytesFromClusters( NewFcb->Vcb, MAXIMUM_RUNS_AT_ONCE ))) {
  269. //
  270. // Log the current state of the file record.
  271. //
  272. FileRecord->Lsn = NtfsWriteLog( IrpContext,
  273. NewFcb->Vcb->MftScb,
  274. FileRecordBcb,
  275. InitializeFileRecordSegment,
  276. FileRecord,
  277. FileRecord->FirstFreeByte,
  278. Noop,
  279. NULL,
  280. 0,
  281. FileOffset,
  282. 0,
  283. 0,
  284. NewFcb->Vcb->BytesPerFileRecordSegment );
  285. *LogIt = TRUE;
  286. }
  287. //
  288. // Write out the new security descriptor
  289. //
  290. NtfsStoreSecurityDescriptor( IrpContext, NewFcb, *LogIt );
  291. //
  292. // And return to our caller
  293. //
  294. DebugTrace( -1, Dbg, ("NtfsAssignSecurity -> VOID\n") );
  295. return;
  296. }
  297. PSHARED_SECURITY
  298. NtfsCacheSharedSecurityByDescriptor (
  299. IN PIRP_CONTEXT IrpContext,
  300. PSECURITY_DESCRIPTOR SecurityDescriptor,
  301. ULONG SecurityDescriptorLength,
  302. IN BOOLEAN RaiseIfInvalid
  303. )
  304. /*++
  305. Routine Description:
  306. This routine finds or constructs a security id and SHARED_SECURITY from
  307. a specific file or directory.
  308. Arguments:
  309. IrpContext - Context of the call
  310. SecurityDescriptor - the actual security descriptor being stored
  311. SecurityDescriptorLength - length of security descriptor
  312. RaiseIfInvalid - raise status if sd is invalid
  313. Return Value:
  314. Referenced shared security.
  315. --*/
  316. {
  317. PSHARED_SECURITY SharedSecurity = NULL;
  318. SECURITY_ID SecurityId;
  319. ULONG FcbSecurityAcquired;
  320. ULONG OwnerCount;
  321. ASSERT_IRP_CONTEXT( IrpContext );
  322. PAGED_CODE();
  323. //
  324. // LEGACY NOTE - this goes away when all volumes become NT 5.0
  325. //
  326. if (IrpContext->Vcb->SecurityDescriptorStream == NULL) {
  327. return NULL;
  328. }
  329. DebugTrace( +1, DbgAcl, ("NtfsCacheSharedSecurityByDescriptor...\n") );
  330. //
  331. // Serialize access to the security cache and use a try/finally to make
  332. // sure we release it
  333. //
  334. NtfsAcquireFcbSecurity( IrpContext->Vcb );
  335. FcbSecurityAcquired = TRUE;
  336. //
  337. // Capture our owner count on the mft - so we can release it if we acquired it later on
  338. // growing the file record for the security stream
  339. //
  340. OwnerCount = NtfsIsSharedScb( IrpContext->Vcb->MftScb );
  341. try {
  342. //
  343. // We have a security descriptor. Create a shared security descriptor.
  344. //
  345. SharedSecurity = GetSharedSecurityFromDescriptorUnsafe( IrpContext,
  346. SecurityDescriptor,
  347. SecurityDescriptorLength,
  348. RaiseIfInvalid );
  349. //
  350. // Make sure the shared security doesn't go away
  351. //
  352. SharedSecurity->ReferenceCount += 1;
  353. DebugTrace( 0, DbgAcl, ("NtfsCacheSharedSecurityByDescriptor bumping refcount %08x\n", SharedSecurity ));
  354. //
  355. // If we found a shared security descriptor with no Id assigned, then
  356. // we must assign it. Since it is known that no Id was assigned we
  357. // must also add it into the cache.
  358. //
  359. if (SharedSecurity->Header.HashKey.SecurityId == SECURITY_ID_INVALID) {
  360. //
  361. // Find unique SecurityId for descriptor and set SecurityId in Fcb.
  362. //
  363. SecurityId = GetSecurityIdFromSecurityDescriptorUnsafe( IrpContext,
  364. SharedSecurity );
  365. ASSERT( SharedSecurity->Header.HashKey.SecurityId == SecurityId );
  366. SharedSecurity->Header.HashKey.SecurityId = SecurityId;
  367. DebugTrace( 0, DbgAcl, ("NtfsCacheSharedSecurityByDescriptor setting security Id to new %08x\n", SecurityId ));
  368. //
  369. // We need to drop the FcbSecurity before performing the checkpoint, to avoid
  370. // deadlocks, but this is ok since we have incremented the reference count on
  371. // our SharedSecurity.
  372. //
  373. NtfsReleaseFcbSecurity( IrpContext->Vcb );
  374. FcbSecurityAcquired = FALSE;
  375. //
  376. // Checkpoint the current transaction so that we can safely add this
  377. // shared security to the cache. Once this call is complete, we are
  378. // guaranteed that the security index modifications make it out to
  379. // disk before the newly allocated security ID does.
  380. //
  381. NtfsCheckpointCurrentTransaction( IrpContext );
  382. //
  383. // Release the security descriptor and mft if owned
  384. //
  385. NtfsReleaseExclusiveScbIfOwned( IrpContext, IrpContext->Vcb->SecurityDescriptorStream );
  386. //
  387. // Check if the mft has been acquired during the call before releasing it
  388. //
  389. if (NtfsIsSharedScb( IrpContext->Vcb->MftScb ) != OwnerCount) {
  390. NtfsReleaseScb( IrpContext, IrpContext->Vcb->MftScb );
  391. }
  392. //
  393. // Cache this shared security for faster access.
  394. //
  395. NtfsAcquireFcbSecurity( IrpContext->Vcb );
  396. FcbSecurityAcquired = TRUE;
  397. AddCachedSharedSecurityUnsafe( IrpContext->Vcb, SharedSecurity );
  398. }
  399. } finally {
  400. if (AbnormalTermination( )) {
  401. if (SharedSecurity != NULL) {
  402. if (!FcbSecurityAcquired) {
  403. NtfsAcquireFcbSecurity( IrpContext->Vcb );
  404. RemoveReferenceSharedSecurityUnsafe( &SharedSecurity );
  405. FcbSecurityAcquired = TRUE;
  406. }
  407. }
  408. }
  409. if (FcbSecurityAcquired) {
  410. NtfsReleaseFcbSecurity( IrpContext->Vcb );
  411. }
  412. }
  413. //
  414. // And return to our caller
  415. //
  416. DebugTrace( -1, DbgAcl, ( "NtfsCacheSharedSecurityByDescriptor -> %08x\n", SharedSecurity ) );
  417. return SharedSecurity;
  418. }
  419. NTSTATUS
  420. NtfsModifySecurity (
  421. IN PIRP_CONTEXT IrpContext,
  422. IN PFCB Fcb,
  423. IN PSECURITY_INFORMATION SecurityInformation,
  424. OUT PSECURITY_DESCRIPTOR SecurityDescriptor
  425. )
  426. /*++
  427. Routine Description:
  428. This routine modifies an existing security descriptor for a file/directory.
  429. Arguments:
  430. Fcb - Supplies the Fcb whose security is being modified
  431. SecurityInformation - Supplies the security information structure passed to
  432. the file system by the I/O system.
  433. SecurityDescriptor - Supplies the security information structure passed to
  434. the file system by the I/O system.
  435. Return Value:
  436. NTSTATUS - Returns an appropriate status value for the function results
  437. --*/
  438. {
  439. NTSTATUS Status;
  440. PSECURITY_DESCRIPTOR DescriptorPtr;
  441. ULONG DescriptorLength;
  442. PSCB Scb;
  443. ASSERT_IRP_CONTEXT( IrpContext );
  444. ASSERT_FCB( Fcb );
  445. PAGED_CODE();
  446. DebugTrace( +1, DbgAcl, ("NtfsModifySecurity...\n") );
  447. //
  448. // First check if we need to load the security descriptor for the file
  449. //
  450. if (Fcb->SharedSecurity == NULL) {
  451. NtfsLoadSecurityDescriptor( IrpContext, Fcb );
  452. }
  453. ASSERT( Fcb->SharedSecurity != NULL);
  454. DescriptorPtr = &Fcb->SharedSecurity->SecurityDescriptor;
  455. //
  456. // Do the modify operation. SeSetSecurityDescriptorInfo no longer
  457. // frees the passed security descriptor.
  458. //
  459. if (!NT_SUCCESS( Status = SeSetSecurityDescriptorInfo( NULL,
  460. SecurityInformation,
  461. SecurityDescriptor,
  462. &DescriptorPtr,
  463. PagedPool,
  464. IoGetFileObjectGenericMapping() ))) {
  465. NtfsRaiseStatus( IrpContext, Status, NULL, NULL );
  466. }
  467. DescriptorLength = RtlLengthSecurityDescriptor( DescriptorPtr );
  468. try {
  469. //
  470. // Check for a zero length.
  471. //
  472. if (DescriptorLength == 0) {
  473. NtfsRaiseStatus( IrpContext, STATUS_INVALID_PARAMETER, NULL, NULL );
  474. }
  475. //
  476. // LEGACY NOTE - remove this test when all volumes go to NT 5
  477. //
  478. if (Fcb->Vcb->SecurityDescriptorStream != NULL) {
  479. PSHARED_SECURITY SharedSecurity;
  480. PSHARED_SECURITY OldSharedSecurity = NULL;
  481. SECURITY_ID OldSecurityId;
  482. ATTRIBUTE_ENUMERATION_CONTEXT AttributeContext;
  483. //
  484. // Cache security descriptor
  485. //
  486. //
  487. // After the SeSetSecurityDescriptorInfo we should have a valid sd
  488. //
  489. ASSERT( SeValidSecurityDescriptor( DescriptorLength, DescriptorPtr ));
  490. SharedSecurity = NtfsCacheSharedSecurityByDescriptor( IrpContext, DescriptorPtr, DescriptorLength, TRUE );
  491. NtfsInitializeAttributeContext( &AttributeContext );
  492. try {
  493. //
  494. // Move Quota to new owner as described in descriptor.
  495. //
  496. NtfsMoveQuotaOwner( IrpContext, Fcb, DescriptorPtr );
  497. //
  498. // Set in new shared security
  499. //
  500. OldSharedSecurity = Fcb->SharedSecurity;
  501. OldSecurityId = Fcb->SecurityId;
  502. Fcb->SharedSecurity = SharedSecurity;
  503. Fcb->SecurityId = SharedSecurity->Header.HashKey.SecurityId;
  504. DebugTrace( 0, DbgAcl, ("NtfsModifySecurity setting Fcb securityId to %08x\n", Fcb->SecurityId ));
  505. //
  506. // We are called to replace an existing security descriptor. In the
  507. // event that we have a downlevel $STANDARD_INFORMATION attribute, we
  508. // must convert it to large form so that the security ID is stored.
  509. //
  510. if (!FlagOn( Fcb->FcbState, FCB_STATE_LARGE_STD_INFO) ) {
  511. DebugTrace( 0, DbgAcl, ("Growing standard information\n") );
  512. NtfsGrowStandardInformation( IrpContext, Fcb );
  513. }
  514. //
  515. // Despite having a large $STANDARD_INFORMATION, we may have
  516. // a security descriptor present. This occurs if the SecurityId
  517. // is invalid
  518. //
  519. if (OldSecurityId == SECURITY_ID_INVALID) {
  520. //
  521. // Read in the security descriptor attribute. If it
  522. // doesn't exist then we're done, otherwise simply delete the
  523. // attribute
  524. //
  525. if (NtfsLookupAttributeByCode( IrpContext,
  526. Fcb,
  527. &Fcb->FileReference,
  528. $SECURITY_DESCRIPTOR,
  529. &AttributeContext )) {
  530. UNICODE_STRING NoName = CONSTANT_UNICODE_STRING( L"" );
  531. DebugTrace( 0, DbgAcl, ("Delete existing Security Descriptor\n") );
  532. NtfsDeleteAttributeRecord( IrpContext,
  533. Fcb,
  534. DELETE_LOG_OPERATION |
  535. DELETE_RELEASE_FILE_RECORD |
  536. DELETE_RELEASE_ALLOCATION,
  537. &AttributeContext );
  538. //
  539. // If the $SECURITY_DESCRIPTOR was non resident, the above
  540. // delete call created one for us under the covers. We
  541. // need to mark it as deleted otherwise, we detect the
  542. // volume as being corrupt.
  543. //
  544. Scb = NtfsCreateScb( IrpContext,
  545. Fcb,
  546. $SECURITY_DESCRIPTOR,
  547. &NoName,
  548. TRUE,
  549. NULL );
  550. if (Scb != NULL) {
  551. ASSERT_EXCLUSIVE_SCB( Scb );
  552. SetFlag( Scb->ScbState, SCB_STATE_ATTRIBUTE_DELETED );
  553. }
  554. }
  555. }
  556. //
  557. // The security descriptor in the FCB is now changed and may not
  558. // reflect what is $STANDARD_INFORMATION. The caller is responsible
  559. // for making this update.
  560. //
  561. } finally {
  562. NtfsCleanupAttributeContext( IrpContext, &AttributeContext );
  563. if (AbnormalTermination()) {
  564. if (OldSharedSecurity != NULL) {
  565. //
  566. // Put back the security the way we found it
  567. //
  568. Fcb->SharedSecurity = OldSharedSecurity;
  569. Fcb->SecurityId = OldSecurityId;
  570. DebugTrace( 0, DbgAcl, ("NtfsModifySecurity resetting Fcb->SecurityId to %08x\n", Fcb->SecurityId ));
  571. }
  572. OldSharedSecurity = SharedSecurity;
  573. }
  574. //
  575. // release old security descriptor (or new one if
  576. // NtfsMoveQuotaOwner raises
  577. //
  578. ASSERT( OldSharedSecurity != NULL );
  579. NtfsAcquireFcbSecurity( Fcb->Vcb );
  580. RemoveReferenceSharedSecurityUnsafe( &OldSharedSecurity );
  581. NtfsReleaseFcbSecurity( Fcb->Vcb );
  582. }
  583. } else {
  584. // LEGACY NOTE - delete this clause when all volumes go to NT 5
  585. //
  586. // Update the move the quota to the new owner if necessary.
  587. //
  588. NtfsMoveQuotaOwner( IrpContext, Fcb, DescriptorPtr );
  589. //
  590. // Load the security descriptor into the Fcb
  591. //
  592. NtfsAcquireFcbSecurity( Fcb->Vcb );
  593. RemoveReferenceSharedSecurityUnsafe( &Fcb->SharedSecurity );
  594. NtfsReleaseFcbSecurity( Fcb->Vcb );
  595. NtfsSetFcbSecurityFromDescriptor(
  596. IrpContext,
  597. Fcb,
  598. DescriptorPtr,
  599. DescriptorLength,
  600. TRUE );
  601. //
  602. // Now we need to store the new security descriptor on disk
  603. //
  604. NtfsStoreSecurityDescriptor( IrpContext, Fcb, TRUE );
  605. }
  606. } finally {
  607. SeDeassignSecurity( &DescriptorPtr );
  608. }
  609. //
  610. // Remember that we modified the security on the file.
  611. //
  612. SetFlag( Fcb->InfoFlags, FCB_INFO_MODIFIED_SECURITY );
  613. //
  614. // And return to our caller
  615. //
  616. DebugTrace( -1, DbgAcl, ("NtfsModifySecurity -> %08lx\n", Status) );
  617. return Status;
  618. }
  619. NTSTATUS
  620. NtfsQuerySecurity (
  621. IN PIRP_CONTEXT IrpContext,
  622. IN PFCB Fcb,
  623. IN PSECURITY_INFORMATION SecurityInformation,
  624. OUT PSECURITY_DESCRIPTOR SecurityDescriptor,
  625. IN OUT PULONG SecurityDescriptorLength
  626. )
  627. /*++
  628. Routine Description:
  629. This routine is used to query the contents of an existing security descriptor for
  630. a file/directory.
  631. Arguments:
  632. Fcb - Supplies the file/directory being queried
  633. SecurityInformation - Supplies the security information structure passed to
  634. the file system by the I/O system.
  635. SecurityDescriptor - Supplies the security information structure passed to
  636. the file system by the I/O system.
  637. SecurityDescriptorLength - Supplies the length of the input security descriptor
  638. buffer in bytes.
  639. Return Value:
  640. NTSTATUS - Returns an appropriate status value for the function results
  641. --*/
  642. {
  643. NTSTATUS Status;
  644. PSECURITY_DESCRIPTOR LocalPointer;
  645. ASSERT_IRP_CONTEXT( IrpContext );
  646. ASSERT_FCB( Fcb );
  647. PAGED_CODE();
  648. DebugTrace( +1, Dbg, ("NtfsQuerySecurity...\n") );
  649. //
  650. // First check if we need to load the security descriptor for the file
  651. //
  652. if (Fcb->SharedSecurity == NULL) {
  653. NtfsLoadSecurityDescriptor( IrpContext, Fcb );
  654. }
  655. LocalPointer = &Fcb->SharedSecurity->SecurityDescriptor;
  656. //
  657. // Now with the security descriptor loaded do the query operation but
  658. // protect ourselves with a exception handler just in case the caller's
  659. // buffer isn't valid
  660. //
  661. try {
  662. Status = SeQuerySecurityDescriptorInfo( SecurityInformation,
  663. SecurityDescriptor,
  664. SecurityDescriptorLength,
  665. &LocalPointer );
  666. } except(EXCEPTION_EXECUTE_HANDLER) {
  667. ExRaiseStatus( STATUS_INVALID_USER_BUFFER );
  668. }
  669. //
  670. // And return to our caller
  671. //
  672. DebugTrace( -1, Dbg, ("NtfsQuerySecurity -> %08lx\n", Status) );
  673. return Status;
  674. }
  675. #define NTFS_SE_CONTROL (((SE_DACL_PRESENT | SE_SELF_RELATIVE) << 16) | SECURITY_DESCRIPTOR_REVISION1)
  676. #define NTFS_DEFAULT_ACCESS_MASK 0x001f01ff
  677. ULONG NtfsWorldAclFile[] = {
  678. 0x00000000, // Null Sacl
  679. 0x00000014, // Dacl
  680. 0x001c0002, // Acl header
  681. 0x00000001, // One ACE
  682. 0x00140000, // ACE Header
  683. NTFS_DEFAULT_ACCESS_MASK,
  684. 0x00000101, // World Sid
  685. 0x01000000,
  686. 0x00000000
  687. };
  688. ULONG NtfsWorldAclDir[] = {
  689. 0x00000000, // Null Sacl
  690. 0x00000014, // Dacl
  691. 0x00300002, // Acl header
  692. 0x00000002, // Two ACEs
  693. 0x00140000, // ACE Header
  694. NTFS_DEFAULT_ACCESS_MASK,
  695. 0x00000101, // World Sid
  696. 0x01000000,
  697. 0x00000000,
  698. 0x00140b00, // ACE Header
  699. NTFS_DEFAULT_ACCESS_MASK,
  700. 0x00000101, // World Sid
  701. 0x01000000,
  702. 0x00000000
  703. };
  704. VOID
  705. NtfsAccessCheck (
  706. PIRP_CONTEXT IrpContext,
  707. IN PFCB Fcb,
  708. IN PFCB ParentFcb OPTIONAL,
  709. IN PIRP Irp,
  710. IN ACCESS_MASK DesiredAccess,
  711. IN BOOLEAN CheckOnly
  712. )
  713. /*++
  714. Routine Description:
  715. This routine does a general access check for the indicated desired access.
  716. This will only be called in the context of an open/create operation.
  717. If access is granted then control is returned to the caller
  718. otherwise this function will do the proper Nt security calls to log
  719. the attempt and then raise an access denied status.
  720. Arguments:
  721. Fcb - Supplies the file/directory being examined
  722. ParentFcb - Optionally supplies the parent of the Fcb being examined
  723. Irp - Supplies the Irp being processed
  724. DesiredAccess - Supplies a mask of the access being requested
  725. CheckOnly - Indicates if this operation is to check the desired access
  726. only and not accumulate the access granted here. In this case we
  727. are guaranteed that we have passed in a hard-wired desired access
  728. and MAXIMUM_ALLOWED will not be one of them.
  729. Return Value:
  730. None.
  731. --*/
  732. {
  733. NTSTATUS Status;
  734. NTSTATUS AccessStatus;
  735. NTSTATUS AccessStatusError;
  736. PACCESS_STATE AccessState;
  737. PIO_STACK_LOCATION IrpSp;
  738. #ifdef NTFS_CACHE_RIGHTS
  739. ACCESS_MASK TmpDesiredAccess;
  740. #endif
  741. KPROCESSOR_MODE EffectiveMode;
  742. BOOLEAN AccessGranted;
  743. ACCESS_MASK GrantedAccess;
  744. PISECURITY_DESCRIPTOR SecurityDescriptor;
  745. PPRIVILEGE_SET Privileges;
  746. PUNICODE_STRING FileName;
  747. PUNICODE_STRING RelatedFileName;
  748. PUNICODE_STRING PartialFileName;
  749. UNICODE_STRING FullFileName;
  750. UNICODE_STRING NormalizedName;
  751. PUNICODE_STRING DeviceObjectName;
  752. USHORT DeviceObjectNameLength;
  753. ULONG FullFileNameLength;
  754. BOOLEAN LeadingSlash;
  755. BOOLEAN RelatedFileNamePresent;
  756. BOOLEAN PartialFileNamePresent;
  757. BOOLEAN MaximumRequested;
  758. BOOLEAN MaximumDeleteAcquired;
  759. BOOLEAN MaximumReadAttrAcquired;
  760. BOOLEAN PerformAccessValidation;
  761. BOOLEAN PerformDeleteAudit;
  762. ASSERT_IRP_CONTEXT( IrpContext );
  763. ASSERT_FCB( Fcb );
  764. ASSERT_IRP( Irp );
  765. PAGED_CODE();
  766. DebugTrace( +1, Dbg, ("NtfsAccessCheck...\n") );
  767. //
  768. // First extract the parts of the Irp that we need to do our checking
  769. //
  770. IrpSp = IoGetCurrentIrpStackLocation(Irp);
  771. AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState;
  772. //
  773. // Check if we need to load the security descriptor for the file
  774. //
  775. if (Fcb->SharedSecurity == NULL) {
  776. NtfsLoadSecurityDescriptor( IrpContext, Fcb );
  777. }
  778. ASSERT( Fcb->SharedSecurity != NULL );
  779. SecurityDescriptor = (PISECURITY_DESCRIPTOR) Fcb->SharedSecurity->SecurityDescriptor;
  780. //
  781. // Check to see if auditing is enabled and if this is the default world ACL.
  782. //
  783. SeLockSubjectContext(&AccessState->SubjectSecurityContext);
  784. if ((*((PULONG) SecurityDescriptor) == NTFS_SE_CONTROL) &&
  785. !SeAuditingFileEventsWithContext( TRUE, SecurityDescriptor, &AccessState->SubjectSecurityContext )) {
  786. //
  787. // Directories and files have different default ACLs.
  788. //
  789. if (((Fcb->Info.FileAttributes & DUP_FILE_NAME_INDEX_PRESENT) &&
  790. RtlEqualMemory( &SecurityDescriptor->Sacl,
  791. NtfsWorldAclDir,
  792. sizeof( NtfsWorldAclDir ))) ||
  793. RtlEqualMemory( &SecurityDescriptor->Sacl,
  794. NtfsWorldAclFile,
  795. sizeof(NtfsWorldAclFile))) {
  796. if (FlagOn( DesiredAccess, MAXIMUM_ALLOWED )) {
  797. GrantedAccess = NTFS_DEFAULT_ACCESS_MASK;
  798. } else {
  799. GrantedAccess = DesiredAccess & NTFS_DEFAULT_ACCESS_MASK;
  800. }
  801. if (!CheckOnly) {
  802. SetFlag( AccessState->PreviouslyGrantedAccess, GrantedAccess );
  803. ClearFlag( AccessState->RemainingDesiredAccess, GrantedAccess | MAXIMUM_ALLOWED );
  804. }
  805. DebugTrace( -1, Dbg, ("NtfsAccessCheck -> DefaultWorldAcl\n") );
  806. SeUnlockSubjectContext(&AccessState->SubjectSecurityContext);
  807. return;
  808. }
  809. }
  810. SeUnlockSubjectContext(&AccessState->SubjectSecurityContext);
  811. Privileges = NULL;
  812. FileName = NULL;
  813. RelatedFileName = NULL;
  814. PartialFileName = NULL;
  815. DeviceObjectName = NULL;
  816. MaximumRequested = FALSE;
  817. MaximumDeleteAcquired = FALSE;
  818. MaximumReadAttrAcquired = FALSE;
  819. PerformAccessValidation = TRUE;
  820. PerformDeleteAudit = FALSE;
  821. RtlZeroMemory( &NormalizedName, sizeof( UNICODE_STRING ) );
  822. //
  823. // Check to see if we need to perform access validation
  824. //
  825. ClearFlag( DesiredAccess, AccessState->PreviouslyGrantedAccess );
  826. #ifdef NTFS_CACHE_RIGHTS
  827. //
  828. // Get any cached knowledge about rights that all callers are known to
  829. // have for this security descriptor.
  830. //
  831. GrantedAccess = NtfsGetCachedRightsWorld( &Fcb->SharedSecurity->CachedRights );
  832. if (!CheckOnly) {
  833. SetFlag( AccessState->PreviouslyGrantedAccess,
  834. FlagOn( DesiredAccess, GrantedAccess ));
  835. }
  836. ClearFlag( DesiredAccess, GrantedAccess );
  837. #endif
  838. if (DesiredAccess == 0) {
  839. //
  840. // Nothing to check, skip AVR and go straight to auditing
  841. //
  842. PerformAccessValidation = FALSE;
  843. AccessGranted = TRUE;
  844. }
  845. //
  846. // Remember the case where MAXIMUM_ALLOWED was requested.
  847. //
  848. if (FlagOn( DesiredAccess, MAXIMUM_ALLOWED )) {
  849. MaximumRequested = TRUE;
  850. }
  851. if (FlagOn( IrpSp->Parameters.Create.SecurityContext->FullCreateOptions, FILE_DELETE_ON_CLOSE )) {
  852. PerformDeleteAudit = TRUE;
  853. }
  854. //
  855. // SL_FORCE_ACCESS_CHECK causes us to use an effective RequestorMode
  856. // of UserMode.
  857. //
  858. EffectiveMode = NtfsEffectiveMode( Irp, IrpSp );
  859. //
  860. // Lock the user context, do the access check and then unlock the context
  861. //
  862. SeLockSubjectContext( &AccessState->SubjectSecurityContext );
  863. //
  864. // Use a try-finally to facilitate cleanup.
  865. //
  866. try {
  867. if (PerformAccessValidation) {
  868. #ifdef NTFS_CACHE_RIGHTS
  869. BOOLEAN EntryCached = FALSE;
  870. //
  871. // Check the cached information only if the effective
  872. // RequestorMode is UserMode.
  873. if (EffectiveMode == UserMode) {
  874. //
  875. // Add in any cached knowledge about rights that this caller
  876. // is known to have for this security descriptor.
  877. //
  878. (VOID)NtfsGetCachedRights( Fcb->Vcb,
  879. &AccessState->SubjectSecurityContext,
  880. Fcb->SharedSecurity,
  881. &GrantedAccess,
  882. &EntryCached,
  883. NULL,
  884. NULL );
  885. //
  886. // Make certain that GrantedAccess has no rights not
  887. // originally requested.
  888. //
  889. ClearFlag( GrantedAccess, ~DesiredAccess );
  890. TmpDesiredAccess = DesiredAccess;
  891. ClearFlag( TmpDesiredAccess, GrantedAccess );
  892. if (EntryCached) {
  893. ClearFlag( TmpDesiredAccess, MAXIMUM_ALLOWED );
  894. }
  895. //
  896. // If all rights are available, then access is granted.
  897. //
  898. if (TmpDesiredAccess == 0) {
  899. AccessGranted = TRUE;
  900. AccessStatus = STATUS_SUCCESS;
  901. //
  902. // Otherwise, we don't know.
  903. //
  904. } else {
  905. AccessGranted = FALSE;
  906. }
  907. } else {
  908. AccessGranted = FALSE;
  909. }
  910. #endif
  911. //
  912. // We need to take the slow path.
  913. //
  914. #ifdef NTFS_CACHE_RIGHTS
  915. if (!AccessGranted) {
  916. #endif
  917. //
  918. // Get the rights information.
  919. //
  920. AccessGranted = SeAccessCheck( &Fcb->SharedSecurity->SecurityDescriptor,
  921. &AccessState->SubjectSecurityContext,
  922. TRUE, // Tokens are locked
  923. DesiredAccess,
  924. 0,
  925. &Privileges,
  926. IoGetFileObjectGenericMapping(),
  927. EffectiveMode,
  928. &GrantedAccess,
  929. &AccessStatus );
  930. if (Privileges != NULL) {
  931. Status = SeAppendPrivileges( AccessState, Privileges );
  932. SeFreePrivileges( Privileges );
  933. Privileges = NULL;
  934. }
  935. #ifdef NTFS_CACHE_RIGHTS
  936. }
  937. #endif
  938. if (AccessGranted) {
  939. ClearFlag( DesiredAccess, GrantedAccess | MAXIMUM_ALLOWED );
  940. if (!CheckOnly) {
  941. SetFlag( AccessState->PreviouslyGrantedAccess, GrantedAccess );
  942. //
  943. // Remember the case where MAXIMUM_ALLOWED was requested and we
  944. // got everything requested from the file.
  945. //
  946. if (MaximumRequested) {
  947. //
  948. // Check whether we got DELETE and READ_ATTRIBUTES. Otherwise
  949. // we will query the parent.
  950. //
  951. if (FlagOn( AccessState->PreviouslyGrantedAccess, DELETE )) {
  952. MaximumDeleteAcquired = TRUE;
  953. }
  954. if (FlagOn( AccessState->PreviouslyGrantedAccess, FILE_READ_ATTRIBUTES )) {
  955. MaximumReadAttrAcquired = TRUE;
  956. }
  957. }
  958. ClearFlag( AccessState->RemainingDesiredAccess, (GrantedAccess | MAXIMUM_ALLOWED) );
  959. }
  960. } else {
  961. AccessStatusError = AccessStatus;
  962. }
  963. //
  964. // Check if the access is not granted and if we were given a parent fcb, and
  965. // if the desired access was asking for delete or file read attributes. If so
  966. // then we need to do some extra work to decide if the caller does get access
  967. // based on the parent directories security descriptor. We also do the same
  968. // work if MAXIMUM_ALLOWED was requested and we didn't get DELETE or
  969. // FILE_READ_ATTRIBUTES.
  970. //
  971. if ((ParentFcb != NULL) &&
  972. ((!AccessGranted && FlagOn( DesiredAccess, DELETE | FILE_READ_ATTRIBUTES )) ||
  973. (MaximumRequested &&
  974. (!MaximumDeleteAcquired || !MaximumReadAttrAcquired)))) {
  975. BOOLEAN DeleteAccessGranted = TRUE;
  976. BOOLEAN ReadAttributesAccessGranted = TRUE;
  977. ACCESS_MASK DeleteChildGrantedAccess = 0;
  978. ACCESS_MASK ListDirectoryGrantedAccess = 0;
  979. //
  980. // Before we proceed load in the parent security descriptor.
  981. // Acquire the parent shared while doing this to protect the
  982. // security descriptor.
  983. //
  984. SeUnlockSubjectContext( &AccessState->SubjectSecurityContext );
  985. NtfsAcquireResourceShared( IrpContext, ParentFcb, TRUE );
  986. SeLockSubjectContext( &AccessState->SubjectSecurityContext );
  987. try {
  988. if (ParentFcb->SharedSecurity == NULL) {
  989. NtfsLoadSecurityDescriptor( IrpContext, ParentFcb );
  990. }
  991. ASSERT( ParentFcb->SharedSecurity != NULL);
  992. //
  993. // Now if the user is asking for delete access then check if the parent
  994. // will granted delete access to the child, and if so then we munge the
  995. // desired access
  996. //
  997. #ifdef NTFS_CACHE_RIGHTS
  998. //
  999. // Check the cached information only if the effective
  1000. // RequestorMode is UserMode.
  1001. //
  1002. if (EffectiveMode == UserMode) {
  1003. //
  1004. // Acquire in any cached knowledge about rights that
  1005. // this caller is known to have for this security
  1006. // descriptor.
  1007. //
  1008. (VOID)NtfsGetCachedRights( ParentFcb->Vcb,
  1009. &AccessState->SubjectSecurityContext,
  1010. ParentFcb->SharedSecurity,
  1011. &GrantedAccess,
  1012. NULL,
  1013. NULL,
  1014. NULL );
  1015. //
  1016. // Add in the results of the parent directory access.
  1017. //
  1018. if (FlagOn( GrantedAccess, FILE_DELETE_CHILD) ) {
  1019. SetFlag( DeleteChildGrantedAccess, DELETE );
  1020. ClearFlag( DesiredAccess, DELETE );
  1021. MaximumDeleteAcquired = TRUE;
  1022. }
  1023. if (FlagOn( GrantedAccess, FILE_LIST_DIRECTORY) ) {
  1024. SetFlag( ListDirectoryGrantedAccess, FILE_READ_ATTRIBUTES );
  1025. ClearFlag( DesiredAccess, FILE_READ_ATTRIBUTES );
  1026. MaximumReadAttrAcquired = TRUE;
  1027. }
  1028. }
  1029. #endif
  1030. if (FlagOn( DesiredAccess, DELETE ) ||
  1031. (MaximumRequested && !MaximumDeleteAcquired)) {
  1032. DeleteAccessGranted = SeAccessCheck( &ParentFcb->SharedSecurity->SecurityDescriptor,
  1033. &AccessState->SubjectSecurityContext,
  1034. TRUE, // Tokens are locked
  1035. FILE_DELETE_CHILD,
  1036. 0,
  1037. &Privileges,
  1038. IoGetFileObjectGenericMapping(),
  1039. EffectiveMode,
  1040. &DeleteChildGrantedAccess,
  1041. &AccessStatus );
  1042. if (Privileges != NULL) {
  1043. SeFreePrivileges( Privileges );
  1044. Privileges = NULL;
  1045. }
  1046. if (DeleteAccessGranted) {
  1047. SetFlag( DeleteChildGrantedAccess, DELETE );
  1048. ClearFlag( DeleteChildGrantedAccess, FILE_DELETE_CHILD );
  1049. ClearFlag( DesiredAccess, DELETE );
  1050. } else {
  1051. AccessStatusError = AccessStatus;
  1052. }
  1053. }
  1054. //
  1055. // Do the same test for read attributes and munge the desired access
  1056. // as appropriate
  1057. //
  1058. if (FlagOn(DesiredAccess, FILE_READ_ATTRIBUTES) ||
  1059. (MaximumRequested && !MaximumReadAttrAcquired)) {
  1060. ReadAttributesAccessGranted = SeAccessCheck( &ParentFcb->SharedSecurity->SecurityDescriptor,
  1061. &AccessState->SubjectSecurityContext,
  1062. TRUE, // Tokens are locked
  1063. FILE_LIST_DIRECTORY,
  1064. 0,
  1065. &Privileges,
  1066. IoGetFileObjectGenericMapping(),
  1067. EffectiveMode,
  1068. &ListDirectoryGrantedAccess,
  1069. &AccessStatus );
  1070. if (Privileges != NULL) {
  1071. SeFreePrivileges( Privileges );
  1072. Privileges = NULL;
  1073. }
  1074. if (ReadAttributesAccessGranted) {
  1075. SetFlag( ListDirectoryGrantedAccess, FILE_READ_ATTRIBUTES );
  1076. ClearFlag( ListDirectoryGrantedAccess, FILE_LIST_DIRECTORY );
  1077. ClearFlag( DesiredAccess, FILE_READ_ATTRIBUTES );
  1078. } else {
  1079. AccessStatusError = AccessStatus;
  1080. }
  1081. }
  1082. } finally {
  1083. NtfsReleaseResource( IrpContext, ParentFcb );
  1084. }
  1085. if (DesiredAccess == 0) {
  1086. //
  1087. // If we got either the delete or list directory access then
  1088. // grant access.
  1089. //
  1090. if (ListDirectoryGrantedAccess != 0 ||
  1091. DeleteChildGrantedAccess != 0) {
  1092. AccessGranted = TRUE;
  1093. }
  1094. } else {
  1095. //
  1096. // Now the desired access has been munged by removing everything the parent
  1097. // has granted so now do the check on the child again
  1098. //
  1099. AccessGranted = SeAccessCheck( &Fcb->SharedSecurity->SecurityDescriptor,
  1100. &AccessState->SubjectSecurityContext,
  1101. TRUE, // Tokens are locked
  1102. DesiredAccess,
  1103. 0,
  1104. &Privileges,
  1105. IoGetFileObjectGenericMapping(),
  1106. EffectiveMode,
  1107. &GrantedAccess,
  1108. &AccessStatus );
  1109. if (Privileges != NULL) {
  1110. Status = SeAppendPrivileges( AccessState, Privileges );
  1111. SeFreePrivileges( Privileges );
  1112. Privileges = NULL;
  1113. }
  1114. //
  1115. // Suppose that we asked for MAXIMUM_ALLOWED and no access was allowed
  1116. // on the file. In that case the call above would fail. It's possible
  1117. // that we were given DELETE or READ_ATTR permission from the
  1118. // parent directory. If we have granted any access and the only remaining
  1119. // desired access is MAXIMUM_ALLOWED then grant this access.
  1120. //
  1121. if (!AccessGranted) {
  1122. AccessStatusError = AccessStatus;
  1123. if (DesiredAccess == MAXIMUM_ALLOWED &&
  1124. (ListDirectoryGrantedAccess != 0 ||
  1125. DeleteChildGrantedAccess != 0)) {
  1126. GrantedAccess = 0;
  1127. AccessGranted = TRUE;
  1128. }
  1129. }
  1130. }
  1131. //
  1132. // If we are given access this time then by definition one of the earlier
  1133. // parent checks had to have succeeded, otherwise we would have failed again
  1134. // and we can update the access state
  1135. //
  1136. if (!CheckOnly && AccessGranted) {
  1137. SetFlag( AccessState->PreviouslyGrantedAccess,
  1138. (GrantedAccess | DeleteChildGrantedAccess | ListDirectoryGrantedAccess) );
  1139. ClearFlag( AccessState->RemainingDesiredAccess,
  1140. (GrantedAccess | MAXIMUM_ALLOWED | DeleteChildGrantedAccess | ListDirectoryGrantedAccess) );
  1141. }
  1142. }
  1143. }
  1144. //
  1145. // Now call a routine that will do the proper open audit/alarm work
  1146. //
  1147. // **** We need to expand the audit alarm code to deal with
  1148. // create and traverse alarms.
  1149. //
  1150. //
  1151. // First we take a shortcut and see if we should bother setting up
  1152. // and making the audit call.
  1153. //
  1154. //
  1155. // NOTE: Calling SeAuditingFileEvents below disables per-user auditing functionality.
  1156. // To make per-user auditing work again, it is necessary to change the call below to
  1157. // be SeAuditingFileOrGlobalEvents, which also takes the subject context.
  1158. //
  1159. // The reason for calling SeAuditingFileEvents here is because per-user auditing is
  1160. // not currently exposed to users, and this routine imposes less of a performance
  1161. // penalty than does calling SeAuditingFileOrGlobalEvents.
  1162. //
  1163. if (SeAuditingFileEventsWithContext( AccessGranted, &Fcb->SharedSecurity->SecurityDescriptor, &AccessState->SubjectSecurityContext )) {
  1164. //
  1165. // Construct the file name. The file name
  1166. // consists of:
  1167. //
  1168. // The device name out of the Vcb +
  1169. //
  1170. // The contents of the filename in the File Object +
  1171. //
  1172. // The contents of the Related File Object if it
  1173. // is present and the name in the File Object
  1174. // does not start with a '\'
  1175. //
  1176. //
  1177. // Obtain the file name.
  1178. //
  1179. PartialFileName = &IrpSp->FileObject->FileName;
  1180. PartialFileNamePresent = (PartialFileName->Length != 0);
  1181. if (!PartialFileNamePresent &&
  1182. FlagOn(IrpSp->Parameters.Create.Options, FILE_OPEN_BY_FILE_ID) ||
  1183. (IrpSp->FileObject->RelatedFileObject != NULL &&
  1184. IrpSp->FileObject->RelatedFileObject->FsContext2 != NULL &&
  1185. FlagOn(((PCCB) IrpSp->FileObject->RelatedFileObject->FsContext2)->Flags,
  1186. CCB_FLAG_OPEN_BY_FILE_ID))) {
  1187. NtfsBuildNormalizedName( IrpContext, Fcb, NULL, &NormalizedName );
  1188. PartialFileNamePresent = TRUE;
  1189. PartialFileName = &NormalizedName;
  1190. }
  1191. //
  1192. // Obtain the device name.
  1193. //
  1194. DeviceObjectName = &Fcb->Vcb->DeviceName;
  1195. DeviceObjectNameLength = DeviceObjectName->Length;
  1196. //
  1197. // Compute how much space we need for the final name string
  1198. //
  1199. FullFileNameLength = (ULONG)DeviceObjectNameLength +
  1200. PartialFileName->Length +
  1201. sizeof( UNICODE_NULL ) +
  1202. sizeof((WCHAR)'\\');
  1203. if ((FullFileNameLength & 0xffff0000L) != 0) {
  1204. NtfsRaiseStatus( IrpContext, STATUS_OBJECT_NAME_INVALID, NULL, NULL );
  1205. }
  1206. FullFileName.MaximumLength = DeviceObjectNameLength +
  1207. PartialFileName->Length +
  1208. sizeof( UNICODE_NULL ) +
  1209. sizeof((WCHAR)'\\');
  1210. //
  1211. // If the partial file name starts with a '\', then don't use
  1212. // whatever may be in the related file name.
  1213. //
  1214. if (PartialFileNamePresent &&
  1215. ((WCHAR)(PartialFileName->Buffer[0]) == L'\\')) {
  1216. LeadingSlash = TRUE;
  1217. } else {
  1218. //
  1219. // Since PartialFileName either doesn't exist or doesn't
  1220. // start with a '\', examine the RelatedFileName to see
  1221. // if it exists.
  1222. //
  1223. LeadingSlash = FALSE;
  1224. if (IrpSp->FileObject->RelatedFileObject != NULL) {
  1225. RelatedFileName = &IrpSp->FileObject->RelatedFileObject->FileName;
  1226. }
  1227. if (RelatedFileNamePresent = ((RelatedFileName != NULL) && (RelatedFileName->Length != 0))) {
  1228. FullFileName.MaximumLength += RelatedFileName->Length;
  1229. }
  1230. }
  1231. FullFileName.Buffer = NtfsAllocatePool(PagedPool, FullFileName.MaximumLength );
  1232. RtlCopyUnicodeString( &FullFileName, DeviceObjectName );
  1233. //
  1234. // RelatedFileNamePresent is not initialized if LeadingSlash == TRUE,
  1235. // but in that case we won't even examine it.
  1236. //
  1237. if (!LeadingSlash && RelatedFileNamePresent) {
  1238. Status = RtlAppendUnicodeStringToString( &FullFileName, RelatedFileName );
  1239. ASSERTMSG("RtlAppendUnicodeStringToString of RelatedFileName", NT_SUCCESS( Status ));
  1240. //
  1241. // RelatedFileName may simply be '\'. Don't append another
  1242. // '\' in this case.
  1243. //
  1244. if (RelatedFileName->Length != sizeof( WCHAR )) {
  1245. FullFileName.Buffer[ (FullFileName.Length / sizeof( WCHAR )) ] = L'\\';
  1246. FullFileName.Length += sizeof(WCHAR);
  1247. }
  1248. }
  1249. if (PartialFileNamePresent) {
  1250. Status = RtlAppendUnicodeStringToString( &FullFileName, PartialFileName );
  1251. //
  1252. // This should not fail
  1253. //
  1254. ASSERTMSG("RtlAppendUnicodeStringToString of PartialFileName failed", NT_SUCCESS( Status ));
  1255. }
  1256. if (PerformDeleteAudit) {
  1257. SeOpenObjectForDeleteAuditAlarm( &FileString,
  1258. NULL,
  1259. &FullFileName,
  1260. &Fcb->SharedSecurity->SecurityDescriptor,
  1261. AccessState,
  1262. FALSE,
  1263. AccessGranted,
  1264. EffectiveMode,
  1265. &AccessState->GenerateOnClose );
  1266. } else {
  1267. SeOpenObjectAuditAlarm( &FileString,
  1268. NULL,
  1269. &FullFileName,
  1270. &Fcb->SharedSecurity->SecurityDescriptor,
  1271. AccessState,
  1272. FALSE,
  1273. AccessGranted,
  1274. EffectiveMode,
  1275. &AccessState->GenerateOnClose );
  1276. }
  1277. NtfsFreePool( FullFileName.Buffer );
  1278. }
  1279. } finally {
  1280. if (NormalizedName.Buffer) {
  1281. NtfsFreePool( NormalizedName.Buffer );
  1282. }
  1283. SeUnlockSubjectContext( &AccessState->SubjectSecurityContext );
  1284. }
  1285. //
  1286. // If access is not granted then we will raise
  1287. //
  1288. if (!AccessGranted) {
  1289. DebugTrace( -1, Dbg, ("NtfsAccessCheck -> Access Denied\n") );
  1290. NtfsRaiseStatus( IrpContext, AccessStatusError, NULL, NULL );
  1291. }
  1292. //
  1293. // And return to our caller
  1294. //
  1295. DebugTrace( -1, Dbg, ("NtfsAccessCheck -> VOID\n") );
  1296. return;
  1297. }
  1298. NTSTATUS
  1299. NtfsCheckFileForDelete (
  1300. IN PIRP_CONTEXT IrpContext,
  1301. IN PSCB ParentScb,
  1302. IN PFCB ThisFcb,
  1303. IN BOOLEAN FcbExisted,
  1304. IN PINDEX_ENTRY IndexEntry
  1305. )
  1306. /*++
  1307. Routine Description:
  1308. This routine checks that the caller has permission to delete the target
  1309. file of a rename or set link operation.
  1310. Arguments:
  1311. ParentScb - This is the parent directory for this file.
  1312. ThisFcb - This is the Fcb for the link being removed.
  1313. FcbExisted - Indicates if this Fcb was just created.
  1314. IndexEntry - This is the index entry on the disk for this file.
  1315. Return Value:
  1316. NTSTATUS - Indicating whether access was granted or the reason access
  1317. was denied.
  1318. --*/
  1319. {
  1320. UNICODE_STRING LastComponentFileName;
  1321. PFILE_NAME IndexFileName;
  1322. PLCB ThisLcb;
  1323. PFCB ParentFcb = ParentScb->Fcb;
  1324. PSCB NextScb = NULL;
  1325. BOOLEAN LcbExisted = FALSE;
  1326. BOOLEAN AccessGranted;
  1327. ACCESS_MASK GrantedAccess;
  1328. NTSTATUS Status = STATUS_SUCCESS;
  1329. BOOLEAN UnlockSubjectContext = FALSE;
  1330. PPRIVILEGE_SET Privileges = NULL;
  1331. PAGED_CODE();
  1332. DebugTrace( +1, Dbg, ("NtfsCheckFileForDelete: Entered\n") );
  1333. ThisLcb = NULL;
  1334. IndexFileName = (PFILE_NAME) NtfsFoundIndexEntry( IndexEntry );
  1335. //
  1336. // If the unclean count is non-zero, we exit with an error.
  1337. //
  1338. if (ThisFcb->CleanupCount != 0) {
  1339. DebugTrace( 0, Dbg, ("Cleanup count of target is non-zero\n") );
  1340. return STATUS_ACCESS_DENIED;
  1341. }
  1342. //
  1343. // We look at the index entry to see if the file is either a directory
  1344. // or a read-only file. We can't delete this for a target directory open.
  1345. //
  1346. if (IsDirectory( &ThisFcb->Info )
  1347. || IsReadOnly( &ThisFcb->Info )) {
  1348. DebugTrace( -1, Dbg, ("NtfsCheckFileForDelete: Read only or directory\n") );
  1349. return STATUS_ACCESS_DENIED;
  1350. }
  1351. //
  1352. // We want to scan through all of the Scb for data streams on this file
  1353. // and look for image sections. We must be able to remove the image section
  1354. // in order to delete the file. Otherwise we can get the case where an
  1355. // active image (with no handle) could be deleted and subsequent faults
  1356. // through the image section will return zeroes.
  1357. //
  1358. if (ThisFcb->LinkCount == 1) {
  1359. BOOLEAN DecrementScb = FALSE;
  1360. //
  1361. // We will increment the Scb count to prevent this Scb from going away
  1362. // if the flush call below generates a close. Use a try-finally to
  1363. // restore the count.
  1364. //
  1365. try {
  1366. while ((NextScb = NtfsGetNextChildScb( ThisFcb, NextScb )) != NULL) {
  1367. InterlockedIncrement( &NextScb->CloseCount );
  1368. DecrementScb = TRUE;
  1369. if (NtfsIsTypeCodeUserData( NextScb->AttributeTypeCode ) &&
  1370. !FlagOn( NextScb->ScbState, SCB_STATE_ATTRIBUTE_DELETED ) &&
  1371. (NextScb->NonpagedScb->SegmentObject.ImageSectionObject != NULL)) {
  1372. if (!MmFlushImageSection( &NextScb->NonpagedScb->SegmentObject,
  1373. MmFlushForDelete )) {
  1374. Status = STATUS_ACCESS_DENIED;
  1375. leave;
  1376. }
  1377. }
  1378. InterlockedDecrement( &NextScb->CloseCount );
  1379. DecrementScb = FALSE;
  1380. }
  1381. } finally {
  1382. if (DecrementScb) {
  1383. InterlockedDecrement( &NextScb->CloseCount );
  1384. }
  1385. }
  1386. if (Status != STATUS_SUCCESS) {
  1387. return Status;
  1388. }
  1389. }
  1390. //
  1391. // We need to check if the link to this file has been deleted. We
  1392. // first check if we definitely know if the link is deleted by
  1393. // looking at the file name flags and the Fcb flags.
  1394. // If that result is uncertain, we need to create an Lcb and
  1395. // check the Lcb flags.
  1396. //
  1397. if (FcbExisted) {
  1398. if (FlagOn( IndexFileName->Flags, FILE_NAME_NTFS | FILE_NAME_DOS )) {
  1399. if (FlagOn( ThisFcb->FcbState, FCB_STATE_PRIMARY_LINK_DELETED )) {
  1400. DebugTrace( -1, Dbg, ("NtfsCheckFileForDelete: Link is going away\n") );
  1401. return STATUS_DELETE_PENDING;
  1402. }
  1403. //
  1404. // This is a Posix link. We need to create the link to test it
  1405. // for deletion.
  1406. //
  1407. } else {
  1408. LastComponentFileName.MaximumLength =
  1409. LastComponentFileName.Length = IndexFileName->FileNameLength * sizeof( WCHAR );
  1410. LastComponentFileName.Buffer = (PWCHAR) IndexFileName->FileName;
  1411. ThisLcb = NtfsCreateLcb( IrpContext,
  1412. ParentScb,
  1413. ThisFcb,
  1414. LastComponentFileName,
  1415. IndexFileName->Flags,
  1416. &LcbExisted );
  1417. //
  1418. // If no Lcb was returned, there's no way that the Lcb has been
  1419. // marked for deletion already.
  1420. //
  1421. if ((ThisLcb != NULL) &&
  1422. (FlagOn( ThisLcb->LcbState, LCB_STATE_DELETE_ON_CLOSE ))) {
  1423. DebugTrace( -1, Dbg, ("NtfsCheckFileForDelete: Link is going away\n") );
  1424. return STATUS_DELETE_PENDING;
  1425. }
  1426. }
  1427. }
  1428. //
  1429. // Finally call the security package to check for delete access.
  1430. // We check for delete access on the target Fcb. If this succeeds, we
  1431. // are done. Otherwise we will check for delete child access on the
  1432. // the parent. Either is sufficient to perform the delete.
  1433. //
  1434. //
  1435. // Check if we need to load the security descriptor for the file
  1436. //
  1437. if (ThisFcb->SharedSecurity == NULL) {
  1438. NtfsLoadSecurityDescriptor( IrpContext, ThisFcb );
  1439. }
  1440. ASSERT( ThisFcb->SharedSecurity != NULL );
  1441. #ifdef NTFS_CACHE_RIGHTS
  1442. //
  1443. // Get any cached knowledge about rights that all callers are known to
  1444. // have for this security descriptor.
  1445. //
  1446. GrantedAccess = NtfsGetCachedRightsWorld( &ThisFcb->SharedSecurity->CachedRights );
  1447. if (FlagOn( GrantedAccess, DELETE )) {
  1448. return STATUS_SUCCESS;
  1449. }
  1450. #endif
  1451. //
  1452. // Use a try-finally to facilitate cleanup.
  1453. //
  1454. try {
  1455. //
  1456. // Lock the user context, do the access check and then unlock the context
  1457. //
  1458. SeLockSubjectContext( IrpContext->Union.SubjectContext );
  1459. UnlockSubjectContext = TRUE;
  1460. #ifdef NTFS_CACHE_RIGHTS
  1461. //
  1462. // Acquire any cached knowledge about rights that this caller
  1463. // is known to have for this security descriptor.
  1464. //
  1465. (VOID)NtfsGetCachedRights( ThisFcb->Vcb,
  1466. IrpContext->Union.SubjectContext,
  1467. ThisFcb->SharedSecurity,
  1468. &GrantedAccess,
  1469. NULL,
  1470. NULL,
  1471. NULL );
  1472. if (FlagOn( GrantedAccess, DELETE )) {
  1473. AccessGranted = TRUE;
  1474. Status = STATUS_SUCCESS;
  1475. } else {
  1476. #endif
  1477. AccessGranted = SeAccessCheck( &ThisFcb->SharedSecurity->SecurityDescriptor,
  1478. IrpContext->Union.SubjectContext,
  1479. TRUE, // Tokens are locked
  1480. DELETE,
  1481. 0,
  1482. &Privileges,
  1483. IoGetFileObjectGenericMapping(),
  1484. UserMode,
  1485. &GrantedAccess,
  1486. &Status );
  1487. #ifdef NTFS_CACHE_RIGHTS
  1488. }
  1489. #endif
  1490. //
  1491. // Check if the access is not granted and if we were given a parent fcb, and
  1492. // if the desired access was asking for delete or file read attributes. If so
  1493. // then we need to do some extra work to decide if the caller does get access
  1494. // based on the parent directories security descriptor
  1495. //
  1496. if (!AccessGranted) {
  1497. //
  1498. // Before we proceed load in the parent security descriptor
  1499. //
  1500. if (ParentFcb->SharedSecurity == NULL) {
  1501. NtfsLoadSecurityDescriptor( IrpContext, ParentFcb );
  1502. }
  1503. ASSERT( ParentFcb->SharedSecurity != NULL);
  1504. //
  1505. // Now if the user is asking for delete access then check if the parent
  1506. // will granted delete access to the child, and if so then we munge the
  1507. // desired access
  1508. //
  1509. #ifdef NTFS_CACHE_RIGHTS
  1510. //
  1511. // Add in any cached knowledge about rights that this caller
  1512. // is known to have for this security descriptor.
  1513. //
  1514. (VOID)NtfsGetCachedRights( ParentFcb->Vcb,
  1515. IrpContext->Union.SubjectContext,
  1516. ParentFcb->SharedSecurity,
  1517. &GrantedAccess,
  1518. NULL,
  1519. NULL,
  1520. NULL );
  1521. if (FlagOn( GrantedAccess, FILE_DELETE_CHILD )) {
  1522. AccessGranted = TRUE;
  1523. Status = STATUS_SUCCESS;
  1524. } else {
  1525. #endif
  1526. AccessGranted = SeAccessCheck( &ParentFcb->SharedSecurity->SecurityDescriptor,
  1527. IrpContext->Union.SubjectContext,
  1528. TRUE, // Tokens are locked
  1529. FILE_DELETE_CHILD,
  1530. 0,
  1531. &Privileges,
  1532. IoGetFileObjectGenericMapping(),
  1533. UserMode,
  1534. &GrantedAccess,
  1535. &Status );
  1536. #ifdef NTFS_CACHE_RIGHTS
  1537. }
  1538. #endif
  1539. }
  1540. } finally {
  1541. DebugUnwind( NtfsCheckFileForDelete );
  1542. if (UnlockSubjectContext) {
  1543. SeUnlockSubjectContext( IrpContext->Union.SubjectContext );
  1544. }
  1545. DebugTrace( -1, Dbg, ("NtfsCheckFileForDelete: Exit\n") );
  1546. }
  1547. return Status;
  1548. }
  1549. VOID
  1550. NtfsCheckIndexForAddOrDelete (
  1551. IN PIRP_CONTEXT IrpContext,
  1552. IN PFCB ParentFcb,
  1553. IN ACCESS_MASK DesiredAccess,
  1554. IN ULONG CreatePrivileges
  1555. )
  1556. /*++
  1557. Routine Description:
  1558. This routine checks if a caller has permission to remove or add a link
  1559. within a directory.
  1560. Arguments:
  1561. ParentFcb - This is the parent directory for the add or delete operation.
  1562. DesiredAccess - Indicates the type of operation. We could be adding or
  1563. removing and entry in the index.
  1564. CreatePriveleges - Backup and restore priveleges captured at create time.
  1565. Return Value:
  1566. None - This routine raises on error.
  1567. --*/
  1568. {
  1569. BOOLEAN AccessGranted;
  1570. ACCESS_MASK GrantedAccess;
  1571. NTSTATUS Status;
  1572. BOOLEAN UnlockSubjectContext = FALSE;
  1573. PPRIVILEGE_SET Privileges = NULL;
  1574. PAGED_CODE();
  1575. DebugTrace( +1, Dbg, ("NtfsCheckIndexForAddOrDelete: Entered\n") );
  1576. //
  1577. // Use a try-finally to facilitate cleanup.
  1578. //
  1579. try {
  1580. //
  1581. // If we have restore privelege then we can add either a file or directory.
  1582. //
  1583. if (FlagOn( CreatePrivileges, TOKEN_HAS_RESTORE_PRIVILEGE )) {
  1584. ClearFlag( DesiredAccess,
  1585. DELETE | FILE_ADD_SUBDIRECTORY | FILE_ADD_FILE );
  1586. }
  1587. //
  1588. // Do a security check if there is more being asked for.
  1589. //
  1590. if (DesiredAccess != 0) {
  1591. //
  1592. // Finally call the security package to check for delete access.
  1593. // We check for delete access on the target Fcb. If this succeeds, we
  1594. // are done. Otherwise we will check for delete child access on the
  1595. // the parent. Either is sufficient to perform the delete.
  1596. //
  1597. //
  1598. // Check if we need to load the security descriptor for the file
  1599. //
  1600. if (ParentFcb->SharedSecurity == NULL) {
  1601. NtfsLoadSecurityDescriptor( IrpContext, ParentFcb );
  1602. }
  1603. ASSERT( ParentFcb->SharedSecurity != NULL );
  1604. #ifdef NTFS_CACHE_RIGHTS
  1605. //
  1606. // Get any cached knowledge about rights that all callers are known to
  1607. // have for this security descriptor.
  1608. //
  1609. GrantedAccess = NtfsGetCachedRightsWorld( &ParentFcb->SharedSecurity->CachedRights );
  1610. ClearFlag( DesiredAccess, GrantedAccess );
  1611. }
  1612. if (DesiredAccess != 0) {
  1613. //
  1614. // Finally call the security package to check for delete access.
  1615. // We check for delete access on the target Fcb. If this succeeds, we
  1616. // are done. Otherwise we will check for delete child access on the
  1617. // the parent. Either is sufficient to perform the delete.
  1618. //
  1619. #endif
  1620. //
  1621. // Capture and lock the user context, do the access check and then unlock the context
  1622. //
  1623. SeLockSubjectContext( IrpContext->Union.SubjectContext );
  1624. UnlockSubjectContext = TRUE;
  1625. #ifdef NTFS_CACHE_RIGHTS
  1626. //
  1627. // Acquire any cached knowledge about rights that this caller
  1628. // is known to have for this security descriptor.
  1629. //
  1630. (VOID)NtfsGetCachedRights( ParentFcb->Vcb,
  1631. IrpContext->Union.SubjectContext,
  1632. ParentFcb->SharedSecurity,
  1633. &GrantedAccess,
  1634. NULL,
  1635. NULL,
  1636. NULL );
  1637. if (FlagOn( GrantedAccess, DELETE )) {
  1638. AccessGranted = TRUE;
  1639. Status = STATUS_SUCCESS;
  1640. } else {
  1641. #endif
  1642. AccessGranted = SeAccessCheck( &ParentFcb->SharedSecurity->SecurityDescriptor,
  1643. IrpContext->Union.SubjectContext,
  1644. TRUE, // Tokens are locked
  1645. DesiredAccess,
  1646. 0,
  1647. &Privileges,
  1648. IoGetFileObjectGenericMapping(),
  1649. UserMode,
  1650. &GrantedAccess,
  1651. &Status );
  1652. //
  1653. // If access is not granted then we will raise
  1654. //
  1655. if (!AccessGranted) {
  1656. DebugTrace( 0, Dbg, ("Access Denied\n") );
  1657. NtfsRaiseStatus( IrpContext, Status, NULL, NULL );
  1658. }
  1659. #ifdef NTFS_CACHE_RIGHTS
  1660. }
  1661. #endif
  1662. }
  1663. } finally {
  1664. DebugUnwind( NtfsCheckIndexForAddOrDelete );
  1665. if (UnlockSubjectContext) {
  1666. SeUnlockSubjectContext( IrpContext->Union.SubjectContext );
  1667. }
  1668. DebugTrace( -1, Dbg, ("NtfsCheckIndexForAddOrDelete: Exit\n") );
  1669. }
  1670. return;
  1671. }
  1672. PSHARED_SECURITY
  1673. GetSharedSecurityFromDescriptorUnsafe (
  1674. IN PIRP_CONTEXT IrpContext,
  1675. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  1676. IN ULONG SecurityDescriptorLength,
  1677. IN BOOLEAN RaiseIfInvalid
  1678. )
  1679. /*++
  1680. Routine Description:
  1681. This routine is called to create or find a shared security structure
  1682. given an security descriptor. We check the parent if present to determine
  1683. if we have a matching security descriptor and reference the existing one if
  1684. so. This routine must be called while holding the Vcb so we can
  1685. safely access the parent structure.
  1686. Arguments:
  1687. IrpContext - context of call
  1688. SecurityId - Id (if known) of security descriptor.
  1689. SecurityDescriptor - Security Descriptor for this file.
  1690. SecurityDescriptorLength - Length of security descriptor for this file
  1691. RaiseIfInvalid - raise if the sd is invalid rather than supplying a default
  1692. used during a create as opposed to an open
  1693. Return Value:
  1694. PSHARED_SECURITY if found, NULL otherwise.
  1695. --*/
  1696. {
  1697. ULONG Hash = 0;
  1698. PSHARED_SECURITY SharedSecurity;
  1699. PAGED_CODE();
  1700. //
  1701. // Make sure the security descriptor we just read in is valid
  1702. //
  1703. if ((SecurityDescriptorLength == 0) ||
  1704. !SeValidSecurityDescriptor( SecurityDescriptorLength, SecurityDescriptor )) {
  1705. if (RaiseIfInvalid) {
  1706. NtfsRaiseStatus( IrpContext, STATUS_INVALID_SECURITY_DESCR, NULL, NULL );
  1707. }
  1708. SecurityDescriptor = NtfsData.DefaultDescriptor;
  1709. SecurityDescriptorLength = NtfsData.DefaultDescriptorLength;
  1710. if (!SeValidSecurityDescriptor( SecurityDescriptorLength, SecurityDescriptor )) {
  1711. NtfsRaiseStatus( IrpContext, STATUS_INVALID_PARAMETER, NULL, NULL );
  1712. }
  1713. }
  1714. //
  1715. // Hash security descriptor. This hash must be position independent to
  1716. // allow for multiple instances of the same descriptor. It is assumed
  1717. // that the bits within the security descriptor are all position
  1718. // independent, i.e, no pointers, all offsets.
  1719. //
  1720. // For speed in the hash, we consider the security descriptor as an array
  1721. // of ULONGs. The fragment at the end that is ignored should not affect
  1722. // the collision nature of this hash.
  1723. //
  1724. {
  1725. PULONG Rover = (PULONG)SecurityDescriptor;
  1726. ULONG Count = SecurityDescriptorLength / 4;
  1727. while (Count--) {
  1728. Hash = ((Hash << 3) | (Hash >> (32-3))) + *Rover++;
  1729. }
  1730. }
  1731. DebugTrace( 0, DbgAcl, ("Hash is %08x\n", Hash) );
  1732. //
  1733. // try to find it by hash
  1734. //
  1735. SharedSecurity = FindCachedSharedSecurityByHashUnsafe( IrpContext->Vcb,
  1736. SecurityDescriptor,
  1737. SecurityDescriptorLength,
  1738. Hash );
  1739. //
  1740. // If we can't find an existing descriptor allocate new pool and copy
  1741. // security descriptor into it.
  1742. //
  1743. if (SharedSecurity == NULL) {
  1744. SharedSecurity = NtfsAllocatePool( PagedPool,
  1745. FIELD_OFFSET( SHARED_SECURITY, SecurityDescriptor )
  1746. + SecurityDescriptorLength );
  1747. SharedSecurity->ReferenceCount = 0;
  1748. //
  1749. // Initialize security index data in shared security
  1750. //
  1751. //
  1752. // Set the security id in the shared structure. If it is not
  1753. // invalid, also cache this shared security structure
  1754. //
  1755. SharedSecurity->Header.HashKey.SecurityId = SECURITY_ID_INVALID;
  1756. SharedSecurity->Header.HashKey.Hash = Hash;
  1757. SetSharedSecurityLength(SharedSecurity, SecurityDescriptorLength);
  1758. SharedSecurity->Header.Offset = (ULONGLONG) 0xFFFFFFFFFFFFFFFFi64;
  1759. RtlCopyMemory( &SharedSecurity->SecurityDescriptor,
  1760. SecurityDescriptor,
  1761. SecurityDescriptorLength );
  1762. #ifdef NTFS_CACHE_RIGHTS
  1763. //
  1764. // Initialize the cached rights.
  1765. //
  1766. RtlZeroMemory( &SharedSecurity->CachedRights,
  1767. sizeof( CACHED_ACCESS_RIGHTS ));
  1768. #endif
  1769. }
  1770. DebugTrace( 0, DbgAcl, ("GetSharedSecurityFromDescriptorUnsafe found %08x with Id %08x\n",
  1771. SharedSecurity, SharedSecurity->Header.HashKey.SecurityId ));
  1772. return SharedSecurity;
  1773. }
  1774. VOID
  1775. NtfsSetFcbSecurityFromDescriptor (
  1776. IN PIRP_CONTEXT IrpContext,
  1777. IN OUT PFCB Fcb,
  1778. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  1779. IN ULONG SecurityDescriptorLength,
  1780. IN BOOLEAN RaiseIfInvalid
  1781. )
  1782. /*++
  1783. Routine Description:
  1784. This routine is called to fill in the shared security structure in
  1785. an Fcb. We check the parent if present to determine if we have
  1786. a matching security descriptor and reference the existing one if
  1787. so. This routine must be called while holding the Vcb so we can
  1788. safely access the parent structure.
  1789. Arguments:
  1790. IrpContext - context of call
  1791. Fcb - Supplies the fcb for the file being operated on
  1792. SecurityDescriptor - Security Descriptor for this file.
  1793. SecurityDescriptorLength - Length of security descriptor for this file
  1794. Return Value:
  1795. None.
  1796. --*/
  1797. {
  1798. PSHARED_SECURITY SharedSecurity;
  1799. PAGED_CODE( );
  1800. NtfsAcquireFcbSecurity( Fcb->Vcb );
  1801. try {
  1802. SharedSecurity = GetSharedSecurityFromDescriptorUnsafe( IrpContext,
  1803. SecurityDescriptor,
  1804. SecurityDescriptorLength,
  1805. RaiseIfInvalid );
  1806. SharedSecurity->ReferenceCount += 1;
  1807. DebugTrace( +1, DbgAcl, ("NtfsSetFcbSecurityFromDescriptor bumping refcount %08x\n", SharedSecurity ));
  1808. ASSERT( Fcb->SharedSecurity == NULL );
  1809. Fcb->SharedSecurity = SharedSecurity;
  1810. AddCachedSharedSecurityUnsafe( IrpContext->Vcb, SharedSecurity );
  1811. } finally {
  1812. NtfsReleaseFcbSecurity( Fcb->Vcb );
  1813. }
  1814. return;
  1815. }
  1816. BOOLEAN
  1817. NtfsNotifyTraverseCheck (
  1818. IN PCCB Ccb,
  1819. IN PFCB Fcb,
  1820. IN PSECURITY_SUBJECT_CONTEXT SubjectContext
  1821. )
  1822. /*++
  1823. Routine Description:
  1824. This routine is the callback routine provided to the dir notify package
  1825. to check that a caller who is watching a tree has traverse access to
  1826. the directory which has the change. This routine is only called
  1827. when traverse access checking was turned on for the open used to
  1828. perform the watch.
  1829. Arguments:
  1830. Ccb - This is the Ccb associated with the directory which is being
  1831. watched.
  1832. Fcb - This is the Fcb for the directory which contains the file being
  1833. modified. We want to walk up the tree from this point and check
  1834. that the caller has traverse access across that directory.
  1835. If not specified then there is no work to do.
  1836. SubjectContext - This is the subject context captured at the time the
  1837. dir notify call was made.
  1838. Return Value:
  1839. BOOLEAN - TRUE if the caller has traverse access to the file which was
  1840. changed. FALSE otherwise.
  1841. --*/
  1842. {
  1843. TOP_LEVEL_CONTEXT TopLevelContext;
  1844. PTOP_LEVEL_CONTEXT ThreadTopLevelContext;
  1845. PFCB TopFcb;
  1846. IRP_CONTEXT LocalIrpContext;
  1847. IRP LocalIrp;
  1848. PIRP_CONTEXT IrpContext;
  1849. BOOLEAN AccessGranted;
  1850. ACCESS_MASK GrantedAccess;
  1851. NTSTATUS Status = STATUS_SUCCESS;
  1852. #ifdef NTFS_CACHE_RIGHTS
  1853. NTSTATUS TokenInfoStatus = STATUS_UNSUCCESSFUL;
  1854. #endif
  1855. PPRIVILEGE_SET Privileges = NULL;
  1856. PAGED_CODE();
  1857. //
  1858. // If we have no Fcb then we can return immediately.
  1859. //
  1860. if (Fcb == NULL) {
  1861. return TRUE;
  1862. }
  1863. IrpContext = &LocalIrpContext;
  1864. NtfsInitializeIrpContext( NULL, TRUE, &IrpContext );
  1865. IrpContext->OriginatingIrp = &LocalIrp;
  1866. IrpContext->Vcb = Fcb->Vcb;
  1867. //
  1868. // Make sure we don't get any pop-ups
  1869. //
  1870. ThreadTopLevelContext = NtfsInitializeTopLevelIrp( &TopLevelContext, TRUE, FALSE );
  1871. ASSERT( ThreadTopLevelContext == &TopLevelContext );
  1872. NtfsUpdateIrpContextWithTopLevel( IrpContext, &TopLevelContext );
  1873. TopFcb = Ccb->Lcb->Fcb;
  1874. //
  1875. // Use a try-except to catch all of the errors.
  1876. //
  1877. try {
  1878. //
  1879. // Always lock the subject context.
  1880. //
  1881. SeLockSubjectContext( SubjectContext );
  1882. //
  1883. // Use a try-finally to perform local cleanup.
  1884. //
  1885. try {
  1886. //
  1887. // We look while walking up the tree.
  1888. //
  1889. do {
  1890. #ifdef NTFS_CACHE_RIGHTS
  1891. LUID ModifiedId;
  1892. LUID TokenId;
  1893. #endif
  1894. PLCB ParentLcb;
  1895. //
  1896. // Since this is a directory it can have only one parent. So
  1897. // we can use any Lcb to walk upwards.
  1898. //
  1899. ParentLcb = CONTAINING_RECORD( Fcb->LcbQueue.Flink,
  1900. LCB,
  1901. FcbLinks );
  1902. Fcb = ParentLcb->Scb->Fcb;
  1903. //
  1904. // Check if we need to load the security descriptor for the file
  1905. //
  1906. if (Fcb->SharedSecurity == NULL) {
  1907. NtfsLoadSecurityDescriptor( IrpContext, Fcb );
  1908. }
  1909. #ifdef NTFS_CACHE_RIGHTS
  1910. //
  1911. // Acquire any cached knowledge about rights that this caller
  1912. // is known to have for this security descriptor.
  1913. //
  1914. // Note that we can trust that TokenId and ModifiedId won't
  1915. // change inside this block of code because we have locked
  1916. // the subject context above.
  1917. //
  1918. if (TokenInfoStatus != STATUS_SUCCESS) {
  1919. //
  1920. // We have not previously acquired the Id information.
  1921. //
  1922. TokenInfoStatus = NtfsGetCachedRights( Fcb->Vcb,
  1923. SubjectContext,
  1924. Fcb->SharedSecurity,
  1925. &GrantedAccess,
  1926. NULL,
  1927. &TokenId,
  1928. &ModifiedId );
  1929. } else {
  1930. NtfsGetCachedRightsById( Fcb->Vcb,
  1931. &TokenId,
  1932. &ModifiedId,
  1933. SubjectContext,
  1934. Fcb->SharedSecurity,
  1935. NULL,
  1936. &GrantedAccess );
  1937. }
  1938. if (FlagOn( GrantedAccess, FILE_TRAVERSE )) {
  1939. AccessGranted = TRUE;
  1940. } else {
  1941. #endif
  1942. AccessGranted = SeAccessCheck( &Fcb->SharedSecurity->SecurityDescriptor,
  1943. SubjectContext,
  1944. TRUE, // Tokens are locked
  1945. FILE_TRAVERSE,
  1946. 0,
  1947. &Privileges,
  1948. IoGetFileObjectGenericMapping(),
  1949. UserMode,
  1950. &GrantedAccess,
  1951. &Status );
  1952. #ifdef NTFS_CACHE_RIGHTS
  1953. }
  1954. #endif
  1955. } while (AccessGranted && (Fcb != TopFcb));
  1956. } finally {
  1957. SeUnlockSubjectContext( SubjectContext );
  1958. }
  1959. } except (NtfsExceptionFilter( IrpContext, GetExceptionInformation() )) {
  1960. NOTHING;
  1961. }
  1962. NtfsCleanupIrpContext( IrpContext, TRUE );
  1963. ASSERT( IoGetTopLevelIrp() != (PIRP) &TopLevelContext );
  1964. return AccessGranted;
  1965. }
  1966. VOID
  1967. NtfsInitializeSecurity (
  1968. IN PIRP_CONTEXT IrpContext,
  1969. IN PVCB Vcb,
  1970. IN PFCB Fcb
  1971. )
  1972. /*++
  1973. Routine Description:
  1974. This routine is called to initialize the security indexes and descriptor
  1975. stream.
  1976. Arguments:
  1977. IrpContext - context of call
  1978. Vcb - Supplies the volume being initialized
  1979. Fcb - Supplies the file containing the seurity indexes and descriptor
  1980. stream.
  1981. Return Value:
  1982. None.
  1983. --*/
  1984. {
  1985. UNICODE_STRING SecurityIdIndexName = CONSTANT_UNICODE_STRING( L"$SII" );
  1986. UNICODE_STRING SecurityDescriptorHashIndexName = CONSTANT_UNICODE_STRING( L"$SDH" );
  1987. UNICODE_STRING SecurityDescriptorStreamName = CONSTANT_UNICODE_STRING( L"$SDS" );
  1988. MAP_HANDLE Map;
  1989. NTSTATUS Status;
  1990. PAGED_CODE( );
  1991. //
  1992. // Open/Create the security descriptor stream
  1993. //
  1994. NtOfsCreateAttribute( IrpContext,
  1995. Fcb,
  1996. SecurityDescriptorStreamName,
  1997. CREATE_OR_OPEN,
  1998. TRUE,
  1999. &Vcb->SecurityDescriptorStream );
  2000. NtfsAcquireSharedScb( IrpContext, Vcb->SecurityDescriptorStream );
  2001. //
  2002. // Load the run information for the Security data stream.
  2003. // Note this call must be done after the stream is nonresident.
  2004. //
  2005. if (!FlagOn( Vcb->SecurityDescriptorStream->ScbState, SCB_STATE_ATTRIBUTE_RESIDENT )) {
  2006. NtfsPreloadAllocation( IrpContext,
  2007. Vcb->SecurityDescriptorStream,
  2008. 0,
  2009. MAXLONGLONG );
  2010. }
  2011. //
  2012. // Open the Security descriptor indexes and storage.
  2013. //
  2014. NtOfsCreateIndex( IrpContext,
  2015. Fcb,
  2016. SecurityIdIndexName,
  2017. CREATE_OR_OPEN,
  2018. 0,
  2019. COLLATION_NTOFS_ULONG,
  2020. NtOfsCollateUlong,
  2021. NULL,
  2022. &Vcb->SecurityIdIndex );
  2023. NtOfsCreateIndex( IrpContext,
  2024. Fcb,
  2025. SecurityDescriptorHashIndexName,
  2026. CREATE_OR_OPEN,
  2027. 0,
  2028. COLLATION_NTOFS_SECURITY_HASH,
  2029. NtOfsCollateSecurityHash,
  2030. NULL,
  2031. &Vcb->SecurityDescriptorHashIndex );
  2032. //
  2033. // Retrieve the next security Id to allocate
  2034. //
  2035. try {
  2036. SECURITY_ID LastSecurityId = 0xFFFFFFFF;
  2037. INDEX_KEY LastKey;
  2038. INDEX_ROW LastRow;
  2039. LastKey.KeyLength = sizeof( SECURITY_ID );
  2040. LastKey.Key = &LastSecurityId;
  2041. Map.Bcb = NULL;
  2042. Status = NtOfsFindLastRecord( IrpContext,
  2043. Vcb->SecurityIdIndex,
  2044. &LastKey,
  2045. &LastRow,
  2046. &Map );
  2047. //
  2048. // If we've found the last key, set the next Id to allocate to be
  2049. // one greater than this last key.
  2050. //
  2051. if (Status == STATUS_SUCCESS) {
  2052. ASSERT( LastRow.KeyPart.KeyLength == sizeof( SECURITY_ID ) );
  2053. if (LastRow.KeyPart.KeyLength != sizeof( SECURITY_ID )) {
  2054. NtfsRaiseStatus( IrpContext, STATUS_DISK_CORRUPT_ERROR, NULL, NULL );
  2055. }
  2056. DebugTrace( 0, DbgAcl, ("Found last security Id in index\n") );
  2057. Vcb->NextSecurityId = *(SECURITY_ID *)LastRow.KeyPart.Key + 1;
  2058. //
  2059. // If the index is empty, then set the next Id to be the beginning of the
  2060. // user range.
  2061. //
  2062. } else if (Status == STATUS_NO_MATCH) {
  2063. DebugTrace( 0, DbgAcl, ("Security Id index is empty\n") );
  2064. Vcb->NextSecurityId = SECURITY_ID_FIRST;
  2065. } else {
  2066. NtfsRaiseStatus( IrpContext, Status, NULL, NULL );
  2067. }
  2068. //
  2069. // Update the fcb info from disk to pick up info changed like the FILE_VIEW_INDEX_PRESENT
  2070. // flags. Then update the duplicate info in the parent fcb (the root)
  2071. //
  2072. NtfsUpdateFcbInfoFromDisk( IrpContext, FALSE, Fcb, NULL );
  2073. NtfsUpdateDuplicateInfo( IrpContext, Fcb, NULL, NULL );
  2074. DebugTrace( 0, DbgAcl, ("NextSecurityId is %x\n", Vcb->NextSecurityId) );
  2075. #if (DBG || defined( NTFS_FREE_ASSERTS ))
  2076. NtfsVerifySecurity( IrpContext, Vcb );
  2077. #endif
  2078. } finally {
  2079. NtOfsReleaseMap( IrpContext, &Map );
  2080. }
  2081. }
  2082. PSHARED_SECURITY
  2083. NtfsCacheSharedSecurityBySecurityId (
  2084. IN PIRP_CONTEXT IrpContext,
  2085. IN PVCB Vcb,
  2086. IN SECURITY_ID SecurityId
  2087. )
  2088. /*++
  2089. Routine Description:
  2090. This routine maps looks up a shared security structure given the security Id by
  2091. looking in the per-Vcb cache or loads it if not present.
  2092. Arguments:
  2093. IrpContext - Context of call
  2094. Vcb - Volume where security Id is cached
  2095. SecurityId - security Id for descriptor that is being retrieved
  2096. Return Value:
  2097. Referenced PSHARED_SECURITY of found descriptor.
  2098. --*/
  2099. {
  2100. PSHARED_SECURITY *Bucket;
  2101. PSHARED_SECURITY SharedSecurity;
  2102. PBCB Bcb;
  2103. PSECURITY_DESCRIPTOR_HEADER SecurityDescriptorHeader;
  2104. PAGED_CODE( );
  2105. NtfsAcquireFcbSecurity( Vcb );
  2106. //
  2107. // Probe the cache by Id
  2108. //
  2109. Bucket = Vcb->SecurityCacheById[SecurityId % VCB_SECURITY_CACHE_BY_ID_SIZE];
  2110. //
  2111. // We get a match under the following conditions.
  2112. //
  2113. // - There is a corresponding entry in the SecurityID array
  2114. // - This entry points to an entry in the SecurityHash array
  2115. // - The entry in the SecurityHash array has the correct SecurityID
  2116. //
  2117. if ((Bucket != NULL) &&
  2118. ((SharedSecurity = *Bucket) != NULL) &&
  2119. (SharedSecurity->Header.HashKey.SecurityId == SecurityId)) {
  2120. DebugTrace( 0, DbgAcl, ("Found cached security descriptor %x %x\n",
  2121. SharedSecurity, SharedSecurity->Header.HashKey.SecurityId) );
  2122. DebugTrace( 0, DbgAcl, ("NtfsCacheSharedSecurityBySecurityId bumping refcount %08x\n", SharedSecurity ));
  2123. //
  2124. // We found the correct shared security. Make sure it cannot go
  2125. // away on us.
  2126. //
  2127. SharedSecurity->ReferenceCount += 1;
  2128. NtfsReleaseFcbSecurity( Vcb );
  2129. return SharedSecurity;
  2130. }
  2131. //
  2132. // If we get here we didn't find a matching descriptor. Throw away
  2133. // the incorrect security descriptor we may have found through the
  2134. // SecurityID array.
  2135. //
  2136. SharedSecurity = NULL;
  2137. NtfsReleaseFcbSecurity( Vcb );
  2138. //
  2139. // If we don't have a security index, then return the default security descriptor.
  2140. // This should only happen in cases of corrupted volumes or security indices.
  2141. //
  2142. if (Vcb->SecurityDescriptorStream == NULL) {
  2143. DebugTrace( 0, 0, ("No security index present in Vcb, using default descriptor\n") );
  2144. return NULL;
  2145. }
  2146. //
  2147. // We don't have the descriptor in the cache and have to load it from disk.
  2148. //
  2149. Bcb = NULL;
  2150. DebugTrace( 0, DbgAcl, ("Looking up security descriptor %x\n", SecurityId) );
  2151. //
  2152. // Lock down the security stream
  2153. //
  2154. NtfsAcquireSharedScb( IrpContext, Vcb->SecurityDescriptorStream );
  2155. //
  2156. // Reacquire the security mutex
  2157. //
  2158. NtfsAcquireFcbSecurity( Vcb );
  2159. try {
  2160. //
  2161. // Consult the Vcb index to map to the security descriptor
  2162. //
  2163. if (!MapSecurityIdToSecurityDescriptorHeaderUnsafe( IrpContext,
  2164. Vcb,
  2165. SecurityId,
  2166. &SecurityDescriptorHeader,
  2167. &Bcb )) {
  2168. //
  2169. // We couldn't find the Id. We generate a security descriptor from
  2170. // the default one.
  2171. //
  2172. leave;
  2173. }
  2174. DebugTrace( 0, DbgAcl, ("Found it at %16I64X\n", SecurityDescriptorHeader->Offset) );
  2175. //
  2176. // Look up the security descriptor by hash (just in case)
  2177. //
  2178. SharedSecurity = FindCachedSharedSecurityByHashUnsafe( Vcb,
  2179. (PSECURITY_DESCRIPTOR) ( SecurityDescriptorHeader + 1 ),
  2180. GETSECURITYDESCRIPTORLENGTH( SecurityDescriptorHeader ),
  2181. SecurityDescriptorHeader->HashKey.Hash );
  2182. //
  2183. // If not found
  2184. //
  2185. if (SharedSecurity == NULL) {
  2186. DebugTrace( 0, DbgAcl, ("Not in hash table, creating new SHARED SECURITY\n") );
  2187. SharedSecurity = NtfsAllocatePool( PagedPool,
  2188. FIELD_OFFSET( SHARED_SECURITY, Header ) + SecurityDescriptorHeader->Length );
  2189. SharedSecurity->ReferenceCount = 0;
  2190. RtlCopyMemory( &SharedSecurity->Header,
  2191. SecurityDescriptorHeader,
  2192. SecurityDescriptorHeader->Length );
  2193. #ifdef NTFS_CACHE_RIGHTS
  2194. //
  2195. // Initialize the cached rights.
  2196. //
  2197. RtlZeroMemory( &SharedSecurity->CachedRights,
  2198. sizeof( CACHED_ACCESS_RIGHTS ));
  2199. #endif
  2200. } else {
  2201. DebugTrace( 0, DbgAcl, ("Found in hash table %x, promoting header\n", SharedSecurity) );
  2202. //
  2203. // We found the descriptor by hash. Perform some consistency checks
  2204. //
  2205. #if DBG
  2206. if (SharedSecurity->Header.HashKey.SecurityId != SECURITY_ID_INVALID &&
  2207. SharedSecurity->Header.HashKey.SecurityId != SecurityId )
  2208. DebugTrace( 0, 0, ("Duplicate hash entry found %x %x\n", SecurityId,
  2209. SharedSecurity->Header.HashKey.SecurityId ));
  2210. #endif
  2211. SharedSecurity->Header = *SecurityDescriptorHeader;
  2212. }
  2213. //
  2214. // reference the security descriptor
  2215. //
  2216. SharedSecurity->ReferenceCount += 1;
  2217. //
  2218. // Regardless of whether we found it by hash (since the earlier Id probe missed)
  2219. // or created it anew. Let's put it back into the cache
  2220. //
  2221. AddCachedSharedSecurityUnsafe( Vcb, SharedSecurity );
  2222. } finally {
  2223. NtfsUnpinBcb( IrpContext, &Bcb );
  2224. NtfsReleaseScb( IrpContext, Vcb->SecurityDescriptorStream );
  2225. //
  2226. // Release access to security cache
  2227. //
  2228. NtfsReleaseFcbSecurity( Vcb );
  2229. }
  2230. //
  2231. // if we did not generate a shared security, then build one from
  2232. // the default security descriptor
  2233. //
  2234. if (SharedSecurity == NULL) {
  2235. DebugTrace( 0, 0, ("Security Id %x not found, using default\n", SecurityId) );
  2236. SharedSecurity = NtfsCacheSharedSecurityByDescriptor( IrpContext,
  2237. NtfsData.DefaultDescriptor,
  2238. NtfsData.DefaultDescriptorLength,
  2239. FALSE );
  2240. }
  2241. return SharedSecurity;
  2242. }
  2243. //
  2244. // Local Support routine
  2245. //
  2246. PSHARED_SECURITY
  2247. FindCachedSharedSecurityByHashUnsafe (
  2248. IN PVCB Vcb,
  2249. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  2250. IN ULONG SecurityDescriptorLength,
  2251. IN ULONG Hash
  2252. )
  2253. /*++
  2254. Routine Description:
  2255. This routine maps looks up a shared security structure given the Hash by
  2256. looking in the per-Vcb cache. This routine assumes exclusive access to the
  2257. security cache.
  2258. Arguments:
  2259. Vcb - Volume where security Id is cached
  2260. SecurityDescriptor - Security descriptor being retrieved
  2261. SecurityDescriptorLength - length of descriptor.
  2262. Hash - Hash for descriptor that is being retrieved
  2263. Return Value:
  2264. PSHARED_SECURITY of found shared descriptor. Otherwise, NULL is returned.
  2265. --*/
  2266. {
  2267. PSHARED_SECURITY SharedSecurity;
  2268. PAGED_CODE( );
  2269. //
  2270. // Hash the hash into the per-volume table
  2271. SharedSecurity = Vcb->SecurityCacheByHash[Hash % VCB_SECURITY_CACHE_BY_HASH_SIZE];
  2272. //
  2273. // If there is no shared descriptor there, then no match
  2274. //
  2275. if (SharedSecurity == NULL) {
  2276. return NULL;
  2277. }
  2278. //
  2279. // if the hash doesn't match then no descriptor found
  2280. //
  2281. if (SharedSecurity->Header.HashKey.Hash != Hash) {
  2282. return NULL;
  2283. }
  2284. //
  2285. // If the lengths don't match then no descriptor found
  2286. //
  2287. if (GetSharedSecurityLength( SharedSecurity ) != SecurityDescriptorLength) {
  2288. return NULL;
  2289. }
  2290. //
  2291. // If the security descriptor bits don't compare then no match
  2292. //
  2293. if (!RtlEqualMemory( SharedSecurity->SecurityDescriptor,
  2294. SecurityDescriptor,
  2295. SecurityDescriptorLength) ) {
  2296. return NULL;
  2297. }
  2298. //
  2299. // The shared security was found
  2300. //
  2301. return SharedSecurity;
  2302. }
  2303. //
  2304. // Local Support routine
  2305. //
  2306. VOID
  2307. AddCachedSharedSecurityUnsafe (
  2308. IN PVCB Vcb,
  2309. PSHARED_SECURITY SharedSecurity
  2310. )
  2311. /*++
  2312. Routine Description:
  2313. This routine adds shared security to the Vcb Cache. This routine assumes
  2314. exclusive access to the security cache. The shared security being added
  2315. may have a ref count of one and may already be in the table.
  2316. Arguments:
  2317. Vcb - Volume where security Id is cached
  2318. SharedSecurity - descriptor to be added to the cache
  2319. Return Value:
  2320. None.
  2321. --*/
  2322. {
  2323. PSHARED_SECURITY *Bucket;
  2324. PSHARED_SECURITY Old;
  2325. PAGED_CODE( );
  2326. //
  2327. // Is there an item already in the hash bucket?
  2328. //
  2329. Bucket = &Vcb->SecurityCacheByHash[SharedSecurity->Header.HashKey.Hash % VCB_SECURITY_CACHE_BY_HASH_SIZE];
  2330. Old = *Bucket;
  2331. //
  2332. // Place it into the bucket and reference it
  2333. //
  2334. *Bucket = SharedSecurity;
  2335. SharedSecurity->ReferenceCount += 1;
  2336. DebugTrace( 0, DbgAcl, ("AddCachedSharedSecurityUnsafe bumping refcount %08x\n", SharedSecurity ));
  2337. //
  2338. // Set up hash to point to bucket
  2339. //
  2340. Vcb->SecurityCacheById[SharedSecurity->Header.HashKey.SecurityId % VCB_SECURITY_CACHE_BY_ID_SIZE] = Bucket;
  2341. //
  2342. // Handle removing the old value from the bucket. We do this after advancing
  2343. // the ReferenceCount above in the case where the item is already in the bucket.
  2344. //
  2345. if (Old != NULL) {
  2346. //
  2347. // Remove and dereference the item in the bucket
  2348. //
  2349. RemoveReferenceSharedSecurityUnsafe( &Old );
  2350. }
  2351. return;
  2352. }
  2353. VOID
  2354. NtOfsPurgeSecurityCache (
  2355. IN PVCB Vcb
  2356. )
  2357. /*++
  2358. Routine Description:
  2359. This routine removes all shared security from the per-Vcb cache.
  2360. Arguments:
  2361. Vcb - Volume where descriptors are cached
  2362. Return Value:
  2363. None.
  2364. --*/
  2365. {
  2366. ULONG i;
  2367. PAGED_CODE( );
  2368. //
  2369. // Serialize access to the security cache
  2370. //
  2371. NtfsAcquireFcbSecurity( Vcb );
  2372. //
  2373. // Walk through the cache looking for cached security
  2374. //
  2375. for (i = 0; i < VCB_SECURITY_CACHE_BY_ID_SIZE; i++)
  2376. {
  2377. if (Vcb->SecurityCacheByHash[i] != NULL) {
  2378. //
  2379. // Remove the reference to the security
  2380. //
  2381. PSHARED_SECURITY SharedSecurity = Vcb->SecurityCacheByHash[i];
  2382. Vcb->SecurityCacheByHash[i] = NULL;
  2383. RemoveReferenceSharedSecurityUnsafe( &SharedSecurity );
  2384. }
  2385. }
  2386. //
  2387. // Release access to the cache
  2388. //
  2389. NtfsReleaseFcbSecurity( Vcb );
  2390. }
  2391. //
  2392. // Local Support routine
  2393. //
  2394. BOOLEAN
  2395. MapSecurityIdToSecurityDescriptorHeaderUnsafe (
  2396. IN PIRP_CONTEXT IrpContext,
  2397. IN PVCB Vcb,
  2398. IN SECURITY_ID SecurityId,
  2399. OUT PSECURITY_DESCRIPTOR_HEADER *SecurityDescriptorHeader,
  2400. OUT PBCB *Bcb
  2401. )
  2402. /*++
  2403. Routine Description:
  2404. This routine maps from a security Id to the descriptor bits stored in the
  2405. security descriptor stream using the security Id index.
  2406. Arguments:
  2407. IrpContext - Context of the call
  2408. Vcb - Volume where descriptor is stored
  2409. SecurityId - security Id for descriptor that is being retrieved
  2410. SecurityDescriptorHeader - returned security descriptor pointer
  2411. Bcb - returned mapping control structure
  2412. Return Value:
  2413. True if the descriptor header was successfully mapped.
  2414. --*/
  2415. {
  2416. SECURITY_DESCRIPTOR_HEADER Header;
  2417. NTSTATUS Status;
  2418. MAP_HANDLE Map;
  2419. INDEX_ROW Row;
  2420. INDEX_KEY Key;
  2421. PSECURITY_DESCRIPTOR SecurityDescriptor;
  2422. PAGED_CODE( );
  2423. DebugTrace( 0, DbgAcl, ("Mapping security ID %08x\n", SecurityId) );
  2424. //
  2425. // Lookup descriptor stream position information.
  2426. // The format of the key is simply the ULONG SecurityId
  2427. //
  2428. Key.KeyLength = sizeof( SecurityId );
  2429. Key.Key = &SecurityId;
  2430. Status = NtOfsFindRecord( IrpContext,
  2431. Vcb->SecurityIdIndex,
  2432. &Key,
  2433. &Row,
  2434. &Map,
  2435. NULL );
  2436. DebugTrace( 0, DbgAcl, ("Security Id lookup status = %08x\n", Status) );
  2437. //
  2438. // If the security Id is not found, we let the called decide if the volume
  2439. // needs fixing or whether a default descriptor should be used.
  2440. //
  2441. if (Status == STATUS_NO_MATCH) {
  2442. return FALSE;
  2443. }
  2444. //
  2445. // Save security descriptor offset and length information
  2446. //
  2447. Header = *(PSECURITY_DESCRIPTOR_HEADER)Row.DataPart.Data;
  2448. ASSERT( Header.HashKey.SecurityId == SecurityId );
  2449. //
  2450. // Release mapping information
  2451. //
  2452. NtOfsReleaseMap( IrpContext, &Map );
  2453. //
  2454. // Make sure that the data is the correct size. This is a true failure case
  2455. // where we must fix the disk up. We can just return false because caller
  2456. // will then use a default sd and chkdsk will replace with the same default
  2457. // when it next verifies the disk
  2458. //
  2459. ASSERT( Row.DataPart.DataLength == sizeof( SECURITY_DESCRIPTOR_HEADER ) );
  2460. if (Row.DataPart.DataLength != sizeof( SECURITY_DESCRIPTOR_HEADER )) {
  2461. DebugTrace( 0, DbgAcl, ("SecurityId data doesn't have the correct length\n") );
  2462. return FALSE;
  2463. }
  2464. //
  2465. // Don't try to map clearly invalid sections of the sds stream
  2466. //
  2467. if (Header.Offset > (ULONGLONG)(Vcb->SecurityDescriptorStream->Header.FileSize.QuadPart) ||
  2468. Header.Offset + Header.Length > (ULONGLONG)(Vcb->SecurityDescriptorStream->Header.FileSize.QuadPart)) {
  2469. DebugTrace( 0, DbgAcl, ("SecurityId data doesn't have a correct position\n") );
  2470. return FALSE;
  2471. }
  2472. //
  2473. // Map security descriptor
  2474. //
  2475. DebugTrace( 0, DbgAcl, ("Mapping security descriptor stream at %I64x, len %x\n",
  2476. Header.Offset, Header.Length) );
  2477. NtfsMapStream(
  2478. IrpContext,
  2479. Vcb->SecurityDescriptorStream,
  2480. Header.Offset,
  2481. Header.Length,
  2482. Bcb,
  2483. SecurityDescriptorHeader );
  2484. //
  2485. // Sanity check the found descriptor
  2486. //
  2487. if (RtlCompareMemory( &Header, *SecurityDescriptorHeader, sizeof( Header )) != sizeof( Header )) {
  2488. DebugTrace( 0, DbgAcl, ("Index data does not match stream header\n") );
  2489. return FALSE;
  2490. }
  2491. //
  2492. // Now actually verify the descriptor is valid. If length is too small (even 0)
  2493. // SeValidSecurityDescriptor will safely return false so we don't need to test this
  2494. // before calling
  2495. //
  2496. SecurityDescriptor = (PSECURITY_DESCRIPTOR) Add2Ptr( (*SecurityDescriptorHeader), sizeof( SECURITY_DESCRIPTOR_HEADER ) );
  2497. if (!SeValidSecurityDescriptor( GETSECURITYDESCRIPTORLENGTH( *SecurityDescriptorHeader ), SecurityDescriptor )) {
  2498. DebugTrace( 0, DbgAcl, ("SecurityId data is not valid\n") );
  2499. return FALSE;
  2500. }
  2501. #if DBG
  2502. {
  2503. ULONG SecurityDescLength;
  2504. SecurityDescLength = RtlLengthSecurityDescriptor( SecurityDescriptor );
  2505. ASSERT( SecurityDescLength == GETSECURITYDESCRIPTORLENGTH( *SecurityDescriptorHeader ) );
  2506. }
  2507. #endif
  2508. return TRUE;
  2509. }
  2510. VOID
  2511. NtfsLoadSecurityDescriptor (
  2512. IN PIRP_CONTEXT IrpContext,
  2513. IN PFCB Fcb
  2514. )
  2515. /*++
  2516. Routine Description:
  2517. This routine loads the shared security descriptor into the fcb for the
  2518. file from disk using either the SecurityId or the $Security_Descriptor
  2519. Arguments:
  2520. Fcb - Supplies the fcb for the file being operated on
  2521. Return Value:
  2522. None.
  2523. --*/
  2524. {
  2525. PAGED_CODE();
  2526. ASSERTMSG("Must only be called with a null value here", Fcb->SharedSecurity == NULL);
  2527. DebugTrace( +1, DbgAcl, ("NtfsLoadSecurityDescriptor...\n") );
  2528. //
  2529. // If the file has a valid SecurityId then retrieve the security descriptor
  2530. // from the security descriptor index
  2531. //
  2532. if ((Fcb->SecurityId != SECURITY_ID_INVALID) &&
  2533. (Fcb->Vcb->SecurityDescriptorStream != NULL)) {
  2534. ASSERT( Fcb->SharedSecurity == NULL );
  2535. Fcb->SharedSecurity = NtfsCacheSharedSecurityBySecurityId( IrpContext,
  2536. Fcb->Vcb,
  2537. Fcb->SecurityId );
  2538. ASSERT( Fcb->SharedSecurity != NULL );
  2539. } else {
  2540. PBCB Bcb = NULL;
  2541. PSECURITY_DESCRIPTOR SecurityDescriptor;
  2542. ULONG SecurityDescriptorLength;
  2543. ATTRIBUTE_ENUMERATION_CONTEXT AttributeContext;
  2544. PATTRIBUTE_RECORD_HEADER Attribute;
  2545. try {
  2546. //
  2547. // Read in the security descriptor attribute, and if it is not present
  2548. // then there then the file is not protected. In that case we will
  2549. // use the default descriptor.
  2550. //
  2551. NtfsInitializeAttributeContext( &AttributeContext );
  2552. if (!NtfsLookupAttributeByCode( IrpContext,
  2553. Fcb,
  2554. &Fcb->FileReference,
  2555. $SECURITY_DESCRIPTOR,
  2556. &AttributeContext )) {
  2557. DebugTrace( 0, DbgAcl, ("Security Descriptor attribute does not exist\n") );
  2558. SecurityDescriptor = NtfsData.DefaultDescriptor;
  2559. SecurityDescriptorLength = NtfsData.DefaultDescriptorLength;
  2560. } else {
  2561. //
  2562. // There must be a security descriptor with a non-zero length; only
  2563. // applies for non-resident descriptors with valid data length.
  2564. //
  2565. Attribute = NtfsFoundAttribute( &AttributeContext );
  2566. if (NtfsIsAttributeResident( Attribute ) ?
  2567. (Attribute->Form.Resident.ValueLength == 0) :
  2568. (Attribute->Form.Nonresident.ValidDataLength == 0)) {
  2569. SecurityDescriptor = NtfsData.DefaultDescriptor;
  2570. SecurityDescriptorLength = NtfsData.DefaultDescriptorLength;
  2571. } else {
  2572. NtfsMapAttributeValue( IrpContext,
  2573. Fcb,
  2574. (PVOID *)&SecurityDescriptor,
  2575. &SecurityDescriptorLength,
  2576. &Bcb,
  2577. &AttributeContext );
  2578. }
  2579. }
  2580. NtfsSetFcbSecurityFromDescriptor(
  2581. IrpContext,
  2582. Fcb,
  2583. SecurityDescriptor,
  2584. SecurityDescriptorLength,
  2585. FALSE );
  2586. } finally {
  2587. DebugUnwind( NtfsLoadSecurityDescriptor );
  2588. //
  2589. // Cleanup our attribute enumeration context and the Bcb
  2590. //
  2591. NtfsCleanupAttributeContext( IrpContext, &AttributeContext );
  2592. NtfsUnpinBcb( IrpContext, &Bcb );
  2593. }
  2594. }
  2595. //
  2596. // And return to our caller
  2597. //
  2598. DebugTrace( -1, DbgAcl, ("NtfsLoadSecurityDescriptor -> VOID\n") );
  2599. return;
  2600. }
  2601. //
  2602. // Local Support routine
  2603. //
  2604. NTSTATUS
  2605. NtOfsMatchSecurityHash (
  2606. IN PINDEX_ROW IndexRow,
  2607. IN OUT PVOID MatchData
  2608. )
  2609. /*++
  2610. Routine Description:
  2611. Test whether an index row is worthy of returning based on its contents as
  2612. a row in the SecurityDescriptorHashIndex.
  2613. Arguments:
  2614. IndexRow - row that is being tested
  2615. MatchData - a PVOID that is the hash function we look for.
  2616. Returns:
  2617. STATUS_SUCCESS if the IndexRow matches
  2618. STATUS_NO_MATCH if the IndexRow does not match, but the enumeration should
  2619. continue
  2620. STATUS_NO_MORE_MATCHES if the IndexRow does not match, and the enumeration
  2621. should terminate
  2622. --*/
  2623. {
  2624. ASSERT(IndexRow->KeyPart.KeyLength == sizeof( SECURITY_HASH_KEY ) );
  2625. PAGED_CODE( );
  2626. if (((PSECURITY_HASH_KEY)IndexRow->KeyPart.Key)->Hash == (ULONG)((ULONG_PTR) MatchData)) {
  2627. return STATUS_SUCCESS;
  2628. } else {
  2629. return STATUS_NO_MORE_MATCHES;
  2630. }
  2631. }
  2632. #if (DBG || defined( NTFS_FREE_ASSERTS ))
  2633. VOID
  2634. NtfsVerifySecurity (
  2635. PIRP_CONTEXT IrpContext,
  2636. PVCB Vcb
  2637. )
  2638. /*++
  2639. Routine Description:
  2640. Scan through all the security descriptors in the sds stream and verify their hash
  2641. values in the sdh stream match
  2642. Arguments:
  2643. IrpContext - context of the call
  2644. SharedSecurity - shared security for a file
  2645. Return Value:
  2646. None.
  2647. --*/
  2648. {
  2649. PSECURITY_DESCRIPTOR_HEADER SdHeader;
  2650. PSECURITY_DESCRIPTOR_HEADER SdHeader2;
  2651. LONGLONG Offset = 0;
  2652. ULONG Length = sizeof( SECURITY_DESCRIPTOR_HEADER );
  2653. PBCB Bcb;
  2654. ULONG Hash;
  2655. ULONG SecurityDescriptorLength;
  2656. INDEX_KEY IndexKey;
  2657. INDEX_ROW FoundRow;
  2658. SECURITY_HASH_KEY HashKey;
  2659. PREAD_CONTEXT ReadContext = NULL;
  2660. ULONG FoundCount = 1;
  2661. UCHAR HashDescriptorHeader[2 * (sizeof( SECURITY_DESCRIPTOR_HEADER ) + sizeof( ULONG ))];
  2662. PSECURITY_DESCRIPTOR SecurityDescriptor;
  2663. NTSTATUS Status = STATUS_SUCCESS;
  2664. //
  2665. // This covers both sds and sdh since they both share the same main resource
  2666. //
  2667. NtfsAcquireSharedScb( IrpContext, IrpContext->Vcb->SecurityDescriptorHashIndex );
  2668. //
  2669. // Enumerate the security hash index
  2670. //
  2671. try {
  2672. HashKey.Hash = 0;
  2673. HashKey.SecurityId = 0;
  2674. IndexKey.KeyLength = sizeof( SECURITY_HASH_KEY );
  2675. IndexKey.Key = &HashKey;
  2676. NtOfsReadRecords( IrpContext,
  2677. IrpContext->Vcb->SecurityDescriptorHashIndex,
  2678. &ReadContext,
  2679. &IndexKey,
  2680. NtOfsMatchAll,
  2681. NULL,
  2682. &FoundCount,
  2683. &FoundRow,
  2684. sizeof( HashDescriptorHeader ),
  2685. &HashDescriptorHeader[0]);
  2686. while ((Status == STATUS_SUCCESS) && (FoundCount == 1)) {
  2687. SdHeader = (PSECURITY_DESCRIPTOR_HEADER)FoundRow.DataPart.Data;
  2688. //
  2689. // Read the raw security descriptor
  2690. //
  2691. NtfsMapStream( IrpContext,
  2692. Vcb->SecurityDescriptorStream,
  2693. SdHeader->Offset,
  2694. SdHeader->Length,
  2695. &Bcb,
  2696. &SdHeader2 );
  2697. //
  2698. // Calculate its hash and length
  2699. //
  2700. SecurityDescriptor = (PSECURITY_DESCRIPTOR) Add2Ptr( SdHeader2, sizeof( SECURITY_DESCRIPTOR_HEADER ) );
  2701. ASSERT( SeValidSecurityDescriptor( SdHeader->Length - sizeof( SECURITY_DESCRIPTOR_HEADER ), SecurityDescriptor ));
  2702. if (SeValidSecurityDescriptor( SdHeader->Length - sizeof( SECURITY_DESCRIPTOR_HEADER ) , SecurityDescriptor )) {
  2703. SecurityDescriptorLength = RtlLengthSecurityDescriptor( SecurityDescriptor );
  2704. NtfsUnpinBcb( IrpContext, &Bcb );
  2705. //
  2706. // Read the raw security descriptor
  2707. //
  2708. NtfsMapStream( IrpContext,
  2709. Vcb->SecurityDescriptorStream,
  2710. SdHeader->Offset,
  2711. SecurityDescriptorLength,
  2712. &Bcb,
  2713. &SdHeader2 );
  2714. SecurityDescriptor = (PSECURITY_DESCRIPTOR) Add2Ptr( SdHeader2, sizeof( SECURITY_DESCRIPTOR_HEADER ) );
  2715. {
  2716. PULONG Rover = (PULONG)SecurityDescriptor;
  2717. ULONG Count = SecurityDescriptorLength / 4;
  2718. Hash = 0;
  2719. while (Count--) {
  2720. Hash = ((Hash << 3) | (Hash >> (32-3))) + *Rover++;
  2721. }
  2722. }
  2723. ASSERT( Hash == SdHeader->HashKey.Hash );
  2724. ASSERT( Hash == SdHeader2->HashKey.Hash );
  2725. ASSERT( SdHeader2->Length == SdHeader->Length );
  2726. ASSERT( SecurityDescriptorLength + sizeof( SECURITY_DESCRIPTOR_HEADER ) == SdHeader->Length );
  2727. }
  2728. NtfsUnpinBcb( IrpContext, &Bcb );
  2729. //
  2730. // Find the next record
  2731. //
  2732. Status = NtOfsReadRecords( IrpContext,
  2733. IrpContext->Vcb->SecurityDescriptorHashIndex,
  2734. &ReadContext,
  2735. NULL,
  2736. NtOfsMatchAll,
  2737. NULL,
  2738. &FoundCount,
  2739. &FoundRow,
  2740. sizeof( HashDescriptorHeader ),
  2741. &HashDescriptorHeader[0]);
  2742. }
  2743. } finally {
  2744. if (ReadContext != NULL) {
  2745. NtOfsFreeReadContext( ReadContext );
  2746. }
  2747. NtfsReleaseScb( IrpContext, IrpContext->Vcb->SecurityDescriptorHashIndex );
  2748. }
  2749. }
  2750. #endif
  2751. //
  2752. // Local Support routine
  2753. //
  2754. VOID
  2755. NtOfsLookupSecurityDescriptorInIndex (
  2756. PIRP_CONTEXT IrpContext,
  2757. IN OUT PSHARED_SECURITY SharedSecurity
  2758. )
  2759. /*++
  2760. Routine Description:
  2761. Look up the security descriptor in the index. If found, return the
  2762. security ID.
  2763. Arguments:
  2764. IrpContext - context of the call
  2765. SharedSecurity - shared security for a file
  2766. Return Value:
  2767. None.
  2768. --*/
  2769. {
  2770. PAGED_CODE( );
  2771. DebugTrace( +1, DbgAcl, ("NtOfsLookupSecurityDescriptorInIndex...\n") );
  2772. //
  2773. // For each matching hash record in the index, see if the actual security
  2774. // security descriptor matches.
  2775. //
  2776. {
  2777. INDEX_KEY IndexKey;
  2778. INDEX_ROW FoundRow;
  2779. PSECURITY_DESCRIPTOR_HEADER Header;
  2780. UCHAR HashDescriptorHeader[2 * (sizeof( SECURITY_DESCRIPTOR_HEADER ) + sizeof( ULONG ))];
  2781. PINDEX_KEY Key = &IndexKey;
  2782. PREAD_CONTEXT ReadContext = NULL;
  2783. ULONG FoundCount = 0;
  2784. PBCB Bcb = NULL;
  2785. IndexKey.KeyLength = sizeof( SharedSecurity->Header.HashKey );
  2786. IndexKey.Key = &SharedSecurity->Header.HashKey.Hash;
  2787. try {
  2788. //
  2789. // We keep reading hash records until we find a hash.
  2790. //
  2791. while (SharedSecurity->Header.HashKey.SecurityId == SECURITY_ID_INVALID) {
  2792. //
  2793. // Read next matching SecurityHashIndex record
  2794. //
  2795. FoundCount = 1;
  2796. NtOfsReadRecords( IrpContext,
  2797. IrpContext->Vcb->SecurityDescriptorHashIndex,
  2798. &ReadContext,
  2799. Key,
  2800. NtOfsMatchSecurityHash,
  2801. ULongToPtr( SharedSecurity->Header.HashKey.Hash ),
  2802. &FoundCount,
  2803. &FoundRow,
  2804. sizeof( HashDescriptorHeader ),
  2805. &HashDescriptorHeader[0]);
  2806. //
  2807. // Set next read to read sequentially rather than explicitly
  2808. // seek.
  2809. //
  2810. Key = NULL;
  2811. //
  2812. // If there were no more records found, then go and establish a
  2813. // a new security Id.
  2814. //
  2815. if (FoundCount == 0) {
  2816. break;
  2817. }
  2818. //
  2819. // Examine the row to see if the descriptors are
  2820. // the same. Verify the cache contents.
  2821. //
  2822. ASSERT( FoundRow.DataPart.DataLength == sizeof( SECURITY_DESCRIPTOR_HEADER ) );
  2823. if (FoundRow.DataPart.DataLength != sizeof( SECURITY_DESCRIPTOR_HEADER )) {
  2824. DebugTrace( 0, DbgAcl, ("Found row has a bad size\n") );
  2825. NtfsRaiseStatus( IrpContext,
  2826. STATUS_DISK_CORRUPT_ERROR,
  2827. NULL, NULL );
  2828. }
  2829. Header = (PSECURITY_DESCRIPTOR_HEADER)FoundRow.DataPart.Data;
  2830. //
  2831. // If the length of the security descriptor in the stream is NOT
  2832. // the same as the current security descriptor, then a match is
  2833. // not possible
  2834. //
  2835. if (SharedSecurity->Header.Length != Header->Length) {
  2836. DebugTrace( 0, DbgAcl, ("Descriptor has wrong length\n") );
  2837. continue;
  2838. }
  2839. //
  2840. // Map security descriptor given descriptor stream position.
  2841. //
  2842. try {
  2843. PSECURITY_DESCRIPTOR_HEADER TestHeader;
  2844. NtfsMapStream( IrpContext,
  2845. IrpContext->Vcb->SecurityDescriptorStream,
  2846. Header->Offset,
  2847. Header->Length,
  2848. &Bcb,
  2849. &TestHeader );
  2850. //
  2851. // Make sure index data matches stream data
  2852. //
  2853. ASSERT( (TestHeader->HashKey.Hash == Header->HashKey.Hash) &&
  2854. (TestHeader->HashKey.SecurityId == Header->HashKey.SecurityId) &&
  2855. (TestHeader->Length == Header->Length) );
  2856. //
  2857. // Compare byte-for-byte the security descriptors. We do not
  2858. // perform any rearranging of descriptors into canonical forms.
  2859. //
  2860. if (RtlEqualMemory( SharedSecurity->SecurityDescriptor,
  2861. TestHeader + 1,
  2862. GetSharedSecurityLength( SharedSecurity )) ) {
  2863. //
  2864. // We have a match. Save the found header
  2865. //
  2866. SharedSecurity->Header = *TestHeader;
  2867. DebugTrace( 0, DbgAcl, ("Reusing indexed security Id %x\n",
  2868. TestHeader->HashKey.SecurityId) );
  2869. leave;
  2870. }
  2871. DebugTrace( 0, 0, ("Descriptors different in bits %x\n", TestHeader->HashKey.SecurityId));
  2872. } finally {
  2873. NtfsUnpinBcb( IrpContext, &Bcb );
  2874. }
  2875. }
  2876. } finally {
  2877. if (ReadContext != NULL) {
  2878. NtOfsFreeReadContext( ReadContext );
  2879. }
  2880. }
  2881. }
  2882. DebugTrace( -1, DbgAcl, ("NtOfsLookupSecurityDescriptorInIndex...Done\n") );
  2883. return;
  2884. }
  2885. //
  2886. // Local Support routine
  2887. //
  2888. SECURITY_ID
  2889. GetSecurityIdFromSecurityDescriptorUnsafe (
  2890. PIRP_CONTEXT IrpContext,
  2891. IN OUT PSHARED_SECURITY SharedSecurity
  2892. )
  2893. /*++
  2894. Routine Description:
  2895. Return the security Id associated with a given security descriptor. If
  2896. there is an existing Id, return it. If no Id exists, create one. This assumes
  2897. security mutex is already acquired
  2898. Arguments:
  2899. IrpContext - context of the call
  2900. SharedSecurity - Shared security used by file
  2901. Return Value:
  2902. SECURITY_ID corresponding to the unique instantiation of the security
  2903. descriptor on the volume.
  2904. --*/
  2905. {
  2906. SECURITY_ID SavedSecurityId;
  2907. LONGLONG DescriptorOffset;
  2908. LONGLONG PaddedDescriptorOffset;
  2909. BOOLEAN IncrementedSecId = FALSE;
  2910. PAGED_CODE( );
  2911. DebugTrace( +1, DbgAcl, ("GetSecurityIdFromSecurityDescriptorUnsafe...\n") );
  2912. //
  2913. // Drop the security mutex since we are going to acquire / extend the descriptor stream
  2914. // and the mutex is basically an end resource. Inc ref. count to keep
  2915. // shared security around
  2916. //
  2917. SharedSecurity->ReferenceCount += 1;
  2918. NtfsReleaseFcbSecurity( IrpContext->Vcb );
  2919. //
  2920. // Find descriptor in indexes/stream
  2921. //
  2922. try {
  2923. //
  2924. // Make sure the data structures don't change underneath us
  2925. //
  2926. NtfsAcquireSharedScb( IrpContext, IrpContext->Vcb->SecurityDescriptorStream );
  2927. //
  2928. // Save next Security Id. This is used if we fail to find the security
  2929. // descriptor in the descriptor stream.
  2930. //
  2931. SavedSecurityId = IrpContext->Vcb->NextSecurityId;
  2932. NtOfsLookupSecurityDescriptorInIndex( IrpContext, SharedSecurity );
  2933. //
  2934. // If we've found the security descriptor in the stream we're done.
  2935. //
  2936. if (SharedSecurity->Header.HashKey.SecurityId != SECURITY_ID_INVALID) {
  2937. leave;
  2938. }
  2939. //
  2940. // The security descriptor is not found. Reacquire the security
  2941. // stream exclusive since we are about to modify it.
  2942. //
  2943. NtfsReleaseScb( IrpContext, IrpContext->Vcb->SecurityDescriptorStream );
  2944. NtfsAcquireExclusiveScb( IrpContext, IrpContext->Vcb->SecurityDescriptorStream );
  2945. //
  2946. // During the short interval above, we did not own the security stream.
  2947. // It is possible that another thread has gotten in and created this
  2948. // descriptor. Therefore, we must probe the indexes again.
  2949. //
  2950. // Rather than perform this expensive test *always*, we saved the next
  2951. // security id to be allocated above. Now that we've obtained the stream
  2952. // exclusive we can check to see if the saved one is the same as the next
  2953. // one. If so, then we need to probe the indexes. Otherwise
  2954. // we know that no modifications have taken place.
  2955. //
  2956. if (SavedSecurityId != IrpContext->Vcb->NextSecurityId) {
  2957. DebugTrace( 0, DbgAcl, ("SecurityId changed, rescanning\n") );
  2958. //
  2959. // The descriptor cache has been edited. We must search again
  2960. //
  2961. NtOfsLookupSecurityDescriptorInIndex( IrpContext, SharedSecurity );
  2962. //
  2963. // If the Id was found this time, simply return it
  2964. //
  2965. if (SharedSecurity->Header.HashKey.SecurityId != SECURITY_ID_INVALID) {
  2966. leave;
  2967. }
  2968. }
  2969. //
  2970. // Allocate security id. This does not need to be logged since we only
  2971. // increment this and initialize this from the max key in the index at
  2972. // mount time.
  2973. //
  2974. SharedSecurity->Header.HashKey.SecurityId = IrpContext->Vcb->NextSecurityId++;
  2975. IncrementedSecId = TRUE;
  2976. //
  2977. // Determine allocation location in descriptor stream. The alignment
  2978. // requirements for security descriptors within the stream are:
  2979. //
  2980. // DWORD alignment
  2981. // Not spanning a VACB_MAPPING_GRANULARITY boundary
  2982. //
  2983. //
  2984. // Get current EOF for descriptor stream. This includes the replicated
  2985. // region. Remove the replicated region (& ~VACB_MAPPING_GRANULARITY)
  2986. //
  2987. #if DBG
  2988. {
  2989. LONGLONG Tmp = NtOfsQueryLength( IrpContext->Vcb->SecurityDescriptorStream );
  2990. ASSERT( Tmp == 0 || (Tmp & VACB_MAPPING_GRANULARITY) );
  2991. }
  2992. #endif
  2993. DescriptorOffset = NtOfsQueryLength( IrpContext->Vcb->SecurityDescriptorStream ) & ~VACB_MAPPING_GRANULARITY;
  2994. //
  2995. // Align to 16 byte boundary.
  2996. //
  2997. PaddedDescriptorOffset =
  2998. SharedSecurity->Header.Offset = BlockAlign( DescriptorOffset, 0x10 );
  2999. DebugTrace( 0,
  3000. DbgAcl,
  3001. ("Allocating SecurityId %x at %016I64x\n",
  3002. SharedSecurity->Header.HashKey.SecurityId,
  3003. SharedSecurity->Header.Offset) );
  3004. //
  3005. // Make sure we don't span a VACB_MAPPING_GRANULARITY boundary and
  3006. // have enough room for a completely-zero header.
  3007. // Compare space left in this vacb view with the space needed for the current
  3008. // record double quad word aligned + an empty header
  3009. //
  3010. if (VACB_MAPPING_GRANULARITY - (PaddedDescriptorOffset & (VACB_MAPPING_GRANULARITY - 1)) <
  3011. BlockAlign( SharedSecurity->Header.Length, 0x10 ) + (ULONG)sizeof( SharedSecurity->Header )) {
  3012. //
  3013. // We are about to span the mapping granularity of the cache manager
  3014. // so we want to place this into the next cache window. However,
  3015. // the following window is where the replicated descriptors are
  3016. // stored. We must advance to the window beyond that.
  3017. //
  3018. SharedSecurity->Header.Offset =
  3019. //
  3020. // Round down to previous VACB_MAPPING GRANULARITY
  3021. //
  3022. (SharedSecurity->Header.Offset & ~(VACB_MAPPING_GRANULARITY - 1))
  3023. //
  3024. // Move past this window and replicated window
  3025. //
  3026. + 2 * VACB_MAPPING_GRANULARITY;
  3027. //
  3028. // The next descriptor offset is used for zeroing out the padding
  3029. //
  3030. PaddedDescriptorOffset = SharedSecurity->Header.Offset - VACB_MAPPING_GRANULARITY;
  3031. }
  3032. //
  3033. // Grow security stream to make room for new descriptor and header. This
  3034. // takes into account the replicated copy of the descriptor.
  3035. //
  3036. NtOfsSetLength( IrpContext,
  3037. IrpContext->Vcb->SecurityDescriptorStream,
  3038. (SharedSecurity->Header.Offset +
  3039. SharedSecurity->Header.Length +
  3040. VACB_MAPPING_GRANULARITY) );
  3041. //
  3042. // Zero out any alignment padding since Chkdsk verifies the replication by
  3043. // doing 256K memcmp's.
  3044. //
  3045. NtOfsPutData( IrpContext,
  3046. IrpContext->Vcb->SecurityDescriptorStream,
  3047. DescriptorOffset + VACB_MAPPING_GRANULARITY,
  3048. (ULONG)(PaddedDescriptorOffset - DescriptorOffset),
  3049. NULL );
  3050. NtOfsPutData( IrpContext,
  3051. IrpContext->Vcb->SecurityDescriptorStream,
  3052. DescriptorOffset,
  3053. (ULONG)(PaddedDescriptorOffset - DescriptorOffset),
  3054. NULL );
  3055. //
  3056. // Put the new descriptor into the stream in both the "normal"
  3057. // place and in the replicated place.
  3058. //
  3059. NtOfsPutData( IrpContext,
  3060. IrpContext->Vcb->SecurityDescriptorStream,
  3061. SharedSecurity->Header.Offset,
  3062. SharedSecurity->Header.Length,
  3063. &SharedSecurity->Header );
  3064. NtOfsPutData( IrpContext,
  3065. IrpContext->Vcb->SecurityDescriptorStream,
  3066. SharedSecurity->Header.Offset + VACB_MAPPING_GRANULARITY,
  3067. SharedSecurity->Header.Length,
  3068. &SharedSecurity->Header );
  3069. //
  3070. // add id->data map
  3071. //
  3072. {
  3073. INDEX_ROW Row;
  3074. Row.KeyPart.KeyLength = sizeof( SharedSecurity->Header.HashKey.SecurityId );
  3075. Row.KeyPart.Key = &SharedSecurity->Header.HashKey.SecurityId;
  3076. Row.DataPart.DataLength = sizeof( SharedSecurity->Header );
  3077. Row.DataPart.Data = &SharedSecurity->Header;
  3078. NtOfsAddRecords( IrpContext,
  3079. IrpContext->Vcb->SecurityIdIndex,
  3080. 1,
  3081. &Row,
  3082. FALSE );
  3083. }
  3084. //
  3085. // add hash|id->data map
  3086. //
  3087. {
  3088. INDEX_ROW Row;
  3089. Row.KeyPart.KeyLength =
  3090. sizeof( SharedSecurity->Header.HashKey );
  3091. Row.KeyPart.Key = &SharedSecurity->Header.HashKey;
  3092. Row.DataPart.DataLength = sizeof( SharedSecurity->Header );
  3093. Row.DataPart.Data = &SharedSecurity->Header;
  3094. NtOfsAddRecords( IrpContext,
  3095. IrpContext->Vcb->SecurityDescriptorHashIndex,
  3096. 1,
  3097. &Row,
  3098. FALSE );
  3099. }
  3100. #if (DBG || defined( NTFS_FREE_ASSERTS ))
  3101. NtfsVerifySecurity( IrpContext, IrpContext->Vcb );
  3102. #endif
  3103. } finally {
  3104. NtfsReleaseScb( IrpContext, IrpContext->Vcb->SecurityDescriptorStream );
  3105. //
  3106. // Reacquire fcb security mutex and deref count
  3107. //
  3108. NtfsAcquireFcbSecurity( IrpContext->Vcb );
  3109. SharedSecurity->ReferenceCount -= 1;
  3110. if (IncrementedSecId && AbnormalTermination()) {
  3111. #ifdef BENL_DBG
  3112. KdPrint(( "NTFS: incremented secid to %x and failing %x\n", IrpContext->Vcb->NextSecurityId, IrpContext->ExceptionStatus ));
  3113. #endif
  3114. }
  3115. }
  3116. DebugTrace( -1,
  3117. DbgAcl,
  3118. ("GetSecurityIdFromSecurityDescriptorUnsafe returns %08x\n",
  3119. SharedSecurity->Header.HashKey.SecurityId) );
  3120. return SharedSecurity->Header.HashKey.SecurityId;
  3121. }
  3122. VOID
  3123. NtfsStoreSecurityDescriptor (
  3124. PIRP_CONTEXT IrpContext,
  3125. IN PFCB Fcb,
  3126. IN BOOLEAN LogIt
  3127. )
  3128. /*++
  3129. Routine Description:
  3130. LEGACY NOTE - this routine disappears when all volumes become NT 5
  3131. This routine stores a new security descriptor already stored in the fcb
  3132. from memory onto the disk.
  3133. Arguments:
  3134. Fcb - Supplies the fcb for the file being operated on
  3135. LogIt - Supplies whether or not the creation of a new security descriptor
  3136. should/ be logged or not. Modifications are always logged. This
  3137. parameter must only be specified as FALSE for a file which is currently
  3138. being created.
  3139. Return Value:
  3140. None.
  3141. Note:
  3142. This will dirty the standard information in the FCB but will not update it on
  3143. disk. The caller needs to bring these into sync.
  3144. --*/
  3145. {
  3146. ATTRIBUTE_ENUMERATION_CONTEXT AttributeContext;
  3147. ATTRIBUTE_ENUMERATION_CONTEXT StdInfoContext;
  3148. BOOLEAN CleanupStdInfoContext = FALSE;
  3149. PAGED_CODE();
  3150. DebugTrace( +1, Dbg, ("NtfsStoreSecurityDescriptor...\n") );
  3151. ASSERT_EXCLUSIVE_FCB( Fcb );
  3152. //
  3153. // Initialize the attribute and find the security attribute
  3154. //
  3155. NtfsInitializeAttributeContext( &AttributeContext );
  3156. try {
  3157. ASSERT( Fcb->Vcb->SecurityDescriptorStream == NULL);
  3158. //
  3159. // Check if the attribute is first being modified or deleted, a null
  3160. // value means that we are deleting the security descriptor
  3161. //
  3162. if (Fcb->SharedSecurity == NULL) {
  3163. DebugTrace( 0, Dbg, ("Security Descriptor is null\n") );
  3164. //
  3165. // If it already doesn't exist then we're done, otherwise simply
  3166. // delete the attribute
  3167. //
  3168. if (NtfsLookupAttributeByCode( IrpContext,
  3169. Fcb,
  3170. &Fcb->FileReference,
  3171. $SECURITY_DESCRIPTOR,
  3172. &AttributeContext )) {
  3173. DebugTrace( 0, Dbg, ("Delete existing Security Descriptor\n") );
  3174. NtfsDeleteAttributeRecord( IrpContext,
  3175. Fcb,
  3176. DELETE_LOG_OPERATION |
  3177. DELETE_RELEASE_FILE_RECORD |
  3178. DELETE_RELEASE_ALLOCATION,
  3179. &AttributeContext );
  3180. }
  3181. leave;
  3182. }
  3183. //
  3184. // At this point we are modifying the security descriptor so read in the
  3185. // security descriptor, if it does not exist then we will need to create
  3186. // one.
  3187. //
  3188. if (!NtfsLookupAttributeByCode( IrpContext,
  3189. Fcb,
  3190. &Fcb->FileReference,
  3191. $SECURITY_DESCRIPTOR,
  3192. &AttributeContext )) {
  3193. DebugTrace( 0, Dbg, ("Create a new Security Descriptor\n") );
  3194. NtfsCleanupAttributeContext( IrpContext, &AttributeContext );
  3195. NtfsInitializeAttributeContext( &AttributeContext );
  3196. NtfsCreateAttributeWithValue( IrpContext,
  3197. Fcb,
  3198. $SECURITY_DESCRIPTOR,
  3199. NULL, // attribute name
  3200. &Fcb->SharedSecurity->SecurityDescriptor,
  3201. GetSharedSecurityLength(Fcb->SharedSecurity),
  3202. 0, // attribute flags
  3203. NULL, // where indexed
  3204. LogIt, // logit
  3205. &AttributeContext );
  3206. //
  3207. // We may be modifying the security descriptor of an NT 5.0 volume.
  3208. // We want to store a SecurityID in the standard information field so
  3209. // that if we reboot on 5.0 NTFS will know where to find the most
  3210. // recent security descriptor.
  3211. //
  3212. if (FlagOn( Fcb->FcbState, FCB_STATE_LARGE_STD_INFO )) {
  3213. LARGE_STANDARD_INFORMATION StandardInformation;
  3214. //
  3215. // Initialize the context structure.
  3216. //
  3217. NtfsInitializeAttributeContext( &StdInfoContext );
  3218. CleanupStdInfoContext = TRUE;
  3219. //
  3220. // Locate the standard information, it must be there.
  3221. //
  3222. if (!NtfsLookupAttributeByCode( IrpContext,
  3223. Fcb,
  3224. &Fcb->FileReference,
  3225. $STANDARD_INFORMATION,
  3226. &StdInfoContext )) {
  3227. DebugTrace( 0, Dbg, ("Can't find standard information\n") );
  3228. NtfsRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR, NULL, Fcb );
  3229. }
  3230. ASSERT( NtfsFoundAttribute( &StdInfoContext )->Form.Resident.ValueLength >= sizeof( LARGE_STANDARD_INFORMATION ));
  3231. //
  3232. // Copy the existing standard information to our buffer.
  3233. //
  3234. RtlCopyMemory( &StandardInformation,
  3235. NtfsAttributeValue( NtfsFoundAttribute( &StdInfoContext )),
  3236. sizeof( LARGE_STANDARD_INFORMATION ));
  3237. StandardInformation.SecurityId = SECURITY_ID_INVALID;
  3238. StandardInformation.OwnerId = 0;
  3239. //
  3240. // Call to change the attribute value.
  3241. //
  3242. NtfsChangeAttributeValue( IrpContext,
  3243. Fcb,
  3244. 0,
  3245. &StandardInformation,
  3246. sizeof( LARGE_STANDARD_INFORMATION ),
  3247. FALSE,
  3248. FALSE,
  3249. FALSE,
  3250. FALSE,
  3251. &StdInfoContext );
  3252. }
  3253. } else {
  3254. DebugTrace( 0, Dbg, ("Change an existing Security Descriptor\n") );
  3255. NtfsChangeAttributeValue( IrpContext,
  3256. Fcb,
  3257. 0, // Value offset
  3258. &Fcb->SharedSecurity->SecurityDescriptor,
  3259. GetSharedSecurityLength( Fcb->SharedSecurity ),
  3260. TRUE, // logit
  3261. TRUE,
  3262. FALSE,
  3263. FALSE,
  3264. &AttributeContext );
  3265. }
  3266. } finally {
  3267. DebugUnwind( NtfsStoreSecurityDescriptor );
  3268. //
  3269. // Cleanup our attribute enumeration context
  3270. //
  3271. NtfsCleanupAttributeContext( IrpContext, &AttributeContext );
  3272. if (CleanupStdInfoContext) {
  3273. NtfsCleanupAttributeContext( IrpContext, &StdInfoContext );
  3274. }
  3275. }
  3276. //
  3277. // And return to our caller
  3278. //
  3279. DebugTrace( -1, Dbg, ("NtfsStoreSecurityDescriptor -> VOID\n") );
  3280. return;
  3281. }
  3282. PSHARED_SECURITY
  3283. NtfsCacheSharedSecurityForCreate (
  3284. IN PIRP_CONTEXT IrpContext,
  3285. IN PFCB ParentFcb
  3286. )
  3287. /*++
  3288. Routine Description:
  3289. This routine finds or constructs a security id and SHARED_SECURITY from
  3290. a specific file or directory.
  3291. Arguments:
  3292. IrpContext - Context of the call
  3293. ParentFcb - Supplies the directory under which the new fcb exists
  3294. Return Value:
  3295. Referenced shared security.
  3296. --*/
  3297. {
  3298. PSECURITY_DESCRIPTOR SecurityDescriptor;
  3299. PSHARED_SECURITY SharedSecurity;
  3300. NTSTATUS Status;
  3301. BOOLEAN IsDirectory;
  3302. PACCESS_STATE AccessState;
  3303. PIO_STACK_LOCATION IrpSp;
  3304. ULONG SecurityDescLength;
  3305. ASSERT_IRP_CONTEXT( IrpContext );
  3306. ASSERT_FCB( ParentFcb );
  3307. PAGED_CODE();
  3308. DebugTrace( +1, DbgAcl, ("NtfsCacheSharedSecurityForCreate...\n") );
  3309. //
  3310. // First decide if we are creating a file or a directory
  3311. //
  3312. IrpSp = IoGetCurrentIrpStackLocation(IrpContext->OriginatingIrp);
  3313. if (FlagOn( IrpSp->Parameters.Create.Options, FILE_DIRECTORY_FILE )) {
  3314. IsDirectory = TRUE;
  3315. } else {
  3316. IsDirectory = FALSE;
  3317. }
  3318. //
  3319. // Extract the parts of the Irp that we need to do our assignment
  3320. //
  3321. AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState;
  3322. //
  3323. // Check if we need to load the security descriptor for the parent.
  3324. //
  3325. if (ParentFcb->SharedSecurity == NULL) {
  3326. NtfsLoadSecurityDescriptor( IrpContext, ParentFcb );
  3327. }
  3328. ASSERT( ParentFcb->SharedSecurity != NULL );
  3329. //
  3330. // Create a new security descriptor for the file and raise if there is
  3331. // an error
  3332. //
  3333. if (!NT_SUCCESS( Status = SeAssignSecurity( &ParentFcb->SharedSecurity->SecurityDescriptor,
  3334. AccessState->SecurityDescriptor,
  3335. &SecurityDescriptor,
  3336. IsDirectory,
  3337. &AccessState->SubjectSecurityContext,
  3338. IoGetFileObjectGenericMapping(),
  3339. PagedPool ))) {
  3340. NtfsRaiseStatus( IrpContext, Status, NULL, NULL );
  3341. }
  3342. SecurityDescLength = RtlLengthSecurityDescriptor( SecurityDescriptor );
  3343. ASSERT( SeValidSecurityDescriptor( SecurityDescLength, SecurityDescriptor ));
  3344. try {
  3345. //
  3346. // Make sure the length is non-zero.
  3347. //
  3348. if (SecurityDescLength == 0) {
  3349. NtfsRaiseStatus( IrpContext, STATUS_INVALID_PARAMETER, NULL, NULL );
  3350. }
  3351. //
  3352. // We have a security descriptor. Create a shared security descriptor.
  3353. //
  3354. SharedSecurity = NtfsCacheSharedSecurityByDescriptor( IrpContext,
  3355. SecurityDescriptor,
  3356. SecurityDescLength,
  3357. TRUE );
  3358. } finally {
  3359. //
  3360. // Free the security descriptor created by Se
  3361. //
  3362. SeDeassignSecurity( &SecurityDescriptor );
  3363. }
  3364. //
  3365. // And return to our caller
  3366. //
  3367. DebugTrace( -1, DbgAcl, ("NtfsCacheSharedSecurityForCreate -> VOID\n") );
  3368. return SharedSecurity;
  3369. }
  3370. /*++
  3371. Routine Descriptions:
  3372. Collation routines for security hash index. Collation occurs by Hash first,
  3373. then security Id
  3374. Arguments:
  3375. Key1 - First key to compare.
  3376. Key2 - Second key to compare.
  3377. CollationData - Optional data to support the collation.
  3378. Return Value:
  3379. LessThan, EqualTo, or Greater than, for how Key1 compares
  3380. with Key2.
  3381. --*/
  3382. FSRTL_COMPARISON_RESULT
  3383. NtOfsCollateSecurityHash (
  3384. IN PINDEX_KEY Key1,
  3385. IN PINDEX_KEY Key2,
  3386. IN PVOID CollationData
  3387. )
  3388. {
  3389. PSECURITY_HASH_KEY HashKey1 = (PSECURITY_HASH_KEY) Key1->Key;
  3390. PSECURITY_HASH_KEY HashKey2 = (PSECURITY_HASH_KEY) Key2->Key;
  3391. UNREFERENCED_PARAMETER(CollationData);
  3392. PAGED_CODE( );
  3393. ASSERT( Key1->KeyLength == sizeof( SECURITY_HASH_KEY ) );
  3394. ASSERT( Key2->KeyLength == sizeof( SECURITY_HASH_KEY ) );
  3395. if (HashKey1->Hash < HashKey2->Hash) {
  3396. return LessThan;
  3397. } else if (HashKey1->Hash > HashKey2->Hash) {
  3398. return GreaterThan;
  3399. } else if (HashKey1->SecurityId < HashKey2->SecurityId) {
  3400. return LessThan;
  3401. } else if (HashKey1->SecurityId > HashKey2->SecurityId) {
  3402. return GreaterThan;
  3403. } else {
  3404. return EqualTo;
  3405. }
  3406. }
  3407. BOOLEAN
  3408. NtfsCanAdministerVolume (
  3409. IN PIRP_CONTEXT IrpContext,
  3410. IN PIRP Irp,
  3411. IN PFCB Fcb,
  3412. IN PSECURITY_DESCRIPTOR TestSecurityDescriptor OPTIONAL,
  3413. IN PULONG TestDesiredAccess OPTIONAL
  3414. )
  3415. /*++
  3416. Routine Descriptions:
  3417. For volume open irps test if the user has enough access to administer the volume
  3418. This means retesting the original requested access
  3419. Arguments:
  3420. Irp - The create irp
  3421. Fcb - The fcb to be tested - this should always be the volumedasd fcb
  3422. TestSecurityDescriptor - If specified then use then apply this descriptor for the
  3423. test.
  3424. TestDesiredAccess - If specified then this is the access to apply.
  3425. Return Value:
  3426. TRUE if the user can administer the volume
  3427. --*/
  3428. {
  3429. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  3430. BOOLEAN ManageAccessGranted;
  3431. ULONG ManageDesiredAccess;
  3432. ULONG ManageGrantedAccess;
  3433. NTSTATUS ManageAccessStatus;
  3434. PPRIVILEGE_SET Privileges = NULL;
  3435. PACCESS_STATE AccessState;
  3436. KPROCESSOR_MODE EffectiveMode;
  3437. PAGED_CODE();
  3438. ASSERT( IrpContext->MajorFunction == IRP_MJ_CREATE );
  3439. ASSERT( Fcb == Fcb->Vcb->VolumeDasdScb->Fcb );
  3440. AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState;
  3441. ManageDesiredAccess = AccessState->OriginalDesiredAccess;
  3442. if (ARGUMENT_PRESENT( TestDesiredAccess )) {
  3443. ManageDesiredAccess = *TestDesiredAccess;
  3444. }
  3445. //
  3446. // SL_FORCE_ACCESS_CHECK causes us to use an effective RequestorMode
  3447. // of UserMode.
  3448. //
  3449. EffectiveMode = NtfsEffectiveMode( Irp, IrpSp );
  3450. //
  3451. // Lock the user context, do the access check and then unlock the context
  3452. //
  3453. SeLockSubjectContext( &AccessState->SubjectSecurityContext );
  3454. try {
  3455. ManageAccessGranted = SeAccessCheck( (ARGUMENT_PRESENT( TestSecurityDescriptor ) ?
  3456. TestSecurityDescriptor :
  3457. &Fcb->SharedSecurity->SecurityDescriptor),
  3458. &AccessState->SubjectSecurityContext,
  3459. TRUE, // Tokens are locked
  3460. ManageDesiredAccess,
  3461. 0,
  3462. &Privileges,
  3463. IoGetFileObjectGenericMapping(),
  3464. EffectiveMode,
  3465. &ManageGrantedAccess,
  3466. &ManageAccessStatus );
  3467. } finally {
  3468. SeUnlockSubjectContext( &AccessState->SubjectSecurityContext );
  3469. }
  3470. if (Privileges != NULL) {
  3471. SeFreePrivileges( Privileges );
  3472. }
  3473. return ManageAccessGranted;
  3474. UNREFERENCED_PARAMETER( IrpContext );
  3475. }
  3476. #ifdef NTFS_CACHE_RIGHTS
  3477. VOID
  3478. NtfsGetCachedRightsById (
  3479. IN PVCB Vcb,
  3480. IN PLUID TokenId,
  3481. IN PLUID ModifiedId,
  3482. IN PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext,
  3483. IN PSHARED_SECURITY SharedSecurity,
  3484. OUT PBOOLEAN EntryCached OPTIONAL,
  3485. OUT PACCESS_MASK Rights
  3486. )
  3487. /*++
  3488. Routine Descriptions:
  3489. This call returns the access rights held by the effective
  3490. ACCESS_TOKEN for the given security information, if available.
  3491. Arguments:
  3492. Vcb - Volume where security Id is cached
  3493. TokenId - The effective token's id.
  3494. ModifiedId - The effective token's modification id.
  3495. SubjectSecurityContext - A pointer to the subject's captured and locked
  3496. security context
  3497. SharedSecurity - Shared security used by file
  3498. EntryCached - If the token-specific rights are cached at all, TRUE is
  3499. optionally returned here, otherwise FALSE is returned.
  3500. Rights - The access rights are returned here. If an entry is not found
  3501. in the cache for the effective token, only the world rights are
  3502. returned.
  3503. Return Value:
  3504. None.
  3505. --*/
  3506. {
  3507. UCHAR Index;
  3508. BOOLEAN AccessGranted;
  3509. BOOLEAN LockHeld = FALSE;
  3510. BOOLEAN IsCached = FALSE;
  3511. NTSTATUS AccessStatus = STATUS_UNSUCCESSFUL;
  3512. ACCESS_MASK GrantedAccess;
  3513. PCACHED_ACCESS_RIGHTS CachedRights;
  3514. PAGED_CODE( );
  3515. NtfsAcquireFcbSecurity( Vcb );
  3516. LockHeld = TRUE;
  3517. try {
  3518. CachedRights = &SharedSecurity->CachedRights;
  3519. *Rights = CachedRights->EveryoneRights;
  3520. //
  3521. // Search the list for the given TokenId.
  3522. // It is assumed that a specific TokenId will only appear
  3523. // once in the cache.
  3524. //
  3525. for (Index = 0;
  3526. Index < CachedRights->Count;
  3527. Index += 1) {
  3528. //
  3529. // Check for a match on TokenId and ModifiedId.
  3530. //
  3531. if (RtlEqualLuid( &CachedRights->TokenRights[Index].TokenId,
  3532. TokenId )) {
  3533. if (RtlEqualLuid( &CachedRights->TokenRights[Index].ModifiedId,
  3534. ModifiedId )) {
  3535. //
  3536. // We have a match.
  3537. //
  3538. SetFlag( *Rights, CachedRights->TokenRights[Index].Rights );
  3539. IsCached = TRUE;
  3540. }
  3541. break;
  3542. }
  3543. }
  3544. //
  3545. // If the entry is not cached, get the maximum rights.
  3546. // Note that it is assumed that this call will not return
  3547. // rights that require privileges, even if they are currently
  3548. // enabled. This is the behavior when only MAXIMUM_ALLOWED
  3549. // is requested.
  3550. //
  3551. if (!IsCached) {
  3552. //
  3553. // Drop our lock across this call.
  3554. //
  3555. NtfsReleaseFcbSecurity( Vcb );
  3556. LockHeld = FALSE;
  3557. AccessGranted = SeAccessCheck( &SharedSecurity->SecurityDescriptor,
  3558. SubjectSecurityContext,
  3559. TRUE, // Tokens are locked
  3560. MAXIMUM_ALLOWED,
  3561. 0,
  3562. NULL,
  3563. IoGetFileObjectGenericMapping(),
  3564. UserMode,
  3565. &GrantedAccess,
  3566. &AccessStatus );
  3567. if (AccessGranted) {
  3568. //
  3569. // Update the cached knowledge about rights that this
  3570. // caller is known to have for this security descriptor.
  3571. //
  3572. NtfsAddCachedRights( Vcb,
  3573. SharedSecurity,
  3574. GrantedAccess,
  3575. TokenId,
  3576. ModifiedId );
  3577. IsCached = TRUE;
  3578. }
  3579. }
  3580. } finally {
  3581. if (LockHeld) {
  3582. NtfsReleaseFcbSecurity( Vcb );
  3583. }
  3584. }
  3585. if (ARGUMENT_PRESENT( EntryCached )) {
  3586. *EntryCached = IsCached;
  3587. }
  3588. return;
  3589. }
  3590. NTSTATUS
  3591. NtfsGetCachedRights (
  3592. IN PVCB Vcb,
  3593. IN PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext,
  3594. IN PSHARED_SECURITY SharedSecurity,
  3595. OUT PACCESS_MASK Rights,
  3596. OUT PBOOLEAN EntryCached OPTIONAL,
  3597. OUT PLUID TokenId OPTIONAL,
  3598. OUT PLUID ModifiedId OPTIONAL
  3599. )
  3600. /*++
  3601. Routine Descriptions:
  3602. This call returns the access rights known to be held by the effective
  3603. ACCESS_TOKEN for the given security information. It is assumed that
  3604. the subject context is locked.
  3605. Arguments:
  3606. Vcb - Volume where security Id is cached
  3607. SubjectSecurityContext - A pointer to the subject's captured and locked
  3608. security context
  3609. SharedSecurity - Shared security used by file
  3610. Rights - The access rights are returned here. If an entry is not found
  3611. in the cache for the effective token, only the world rights are
  3612. returned.
  3613. EntryCached - If the token-specific rights are cached at all, TRUE is
  3614. optionally returned here, otherwise FALSE is returned.
  3615. TokenId - The effective token's id is optionally returned here.
  3616. ModifiedId - The effective token's modification id is optionally
  3617. returned here.
  3618. Return Value:
  3619. NTSTATUS - Returns STATUS_SUCCESS if and only if we have obtained at
  3620. least the TokenId and ModifiedId information.
  3621. --*/
  3622. {
  3623. NTSTATUS Status;
  3624. PACCESS_TOKEN EToken;
  3625. PTOKEN_STATISTICS Info = NULL;
  3626. PAGED_CODE( );
  3627. DebugTrace( +1, Dbg, ("NtfsGetCachedRights...\n") );
  3628. //
  3629. // First obtain the effective token's id and modification id.
  3630. //
  3631. EToken = SeQuerySubjectContextToken( SubjectSecurityContext );
  3632. Status = SeQueryInformationToken( EToken, TokenStatistics, &Info );
  3633. //
  3634. // If we have the TokenId and ModifiedId, get the cached rights.
  3635. //
  3636. if (Status == STATUS_SUCCESS) {
  3637. NtfsGetCachedRightsById( Vcb,
  3638. &Info->TokenId,
  3639. &Info->ModifiedId,
  3640. SubjectSecurityContext,
  3641. SharedSecurity,
  3642. EntryCached,
  3643. Rights );
  3644. //
  3645. // Return the Tokenid and ModifiedId to the caller.
  3646. //
  3647. if (ARGUMENT_PRESENT( TokenId )) {
  3648. RtlCopyLuid( TokenId, &Info->TokenId );
  3649. }
  3650. if (ARGUMENT_PRESENT( ModifiedId )) {
  3651. RtlCopyLuid( ModifiedId, &Info->ModifiedId );
  3652. }
  3653. } else {
  3654. //
  3655. // Just return the rights everyone is known to have.
  3656. //
  3657. *Rights = SharedSecurity->CachedRights.EveryoneRights;
  3658. if (ARGUMENT_PRESENT( EntryCached )) {
  3659. *EntryCached = FALSE;
  3660. }
  3661. }
  3662. if (Info != NULL) {
  3663. ExFreePool( Info );
  3664. }
  3665. DebugTrace( -1, Dbg, ("NtfsGetCachedRights -> %08lx, Rights=%08lx\n", Status, *Rights) );
  3666. return Status;
  3667. }
  3668. VOID
  3669. NtfsAddCachedRights (
  3670. IN PVCB Vcb,
  3671. IN PSHARED_SECURITY SharedSecurity,
  3672. IN ACCESS_MASK Rights,
  3673. IN PLUID TokenId,
  3674. IN PLUID ModifiedId
  3675. )
  3676. /*++
  3677. Routine Descriptions:
  3678. This call caches the access rights held by the effective ACCESS_TOKEN
  3679. for the given security information. It is assumed that the subject
  3680. context is locked.
  3681. Arguments:
  3682. Vcb - Volume where security Id is cached
  3683. SharedSecurity - Shared security used by file
  3684. Rights - The access rights.
  3685. TokenId - The effective token's id.
  3686. ModifiedId - The effective token's modification id.
  3687. Return Value:
  3688. None.
  3689. --*/
  3690. {
  3691. BOOLEAN GetEveryoneRights = FALSE;
  3692. UCHAR Index;
  3693. PCACHED_ACCESS_RIGHTS CachedRights;
  3694. PAGED_CODE( );
  3695. DebugTrace( +1, Dbg, ("NtfsAddCachedRights...\n") );
  3696. //
  3697. // Make certain that MAXIMUM_ALLOWED is not in the rights.
  3698. //
  3699. ClearFlag( Rights, MAXIMUM_ALLOWED );
  3700. //
  3701. // Acquire the security mutex
  3702. //
  3703. NtfsAcquireFcbSecurity( Vcb );
  3704. try {
  3705. //
  3706. // Search the list for the given TokenId.
  3707. // It is assumed that a specific TokenId will only appear
  3708. // once in the cache.
  3709. //
  3710. for (Index = 0, CachedRights = &SharedSecurity->CachedRights;
  3711. Index < CachedRights->Count;
  3712. Index += 1) {
  3713. //
  3714. // Check for a match on TokenId and ModifiedId.
  3715. //
  3716. if (RtlEqualLuid( &CachedRights->TokenRights[Index].TokenId,
  3717. TokenId )) {
  3718. //
  3719. // Replace ModifiedId if it doesn't match. That will
  3720. // happen when the token's enabled groups or privileges
  3721. // have changed since the last time we cached information
  3722. // for it.
  3723. //
  3724. if (!RtlEqualLuid( &CachedRights->TokenRights[Index].ModifiedId,
  3725. ModifiedId )) {
  3726. RtlCopyLuid( &CachedRights->TokenRights[Index].ModifiedId,
  3727. ModifiedId );
  3728. }
  3729. //
  3730. // We have a match. Set the rights.
  3731. //
  3732. CachedRights->TokenRights[Index].Rights = Rights;
  3733. //
  3734. // Remember the next entry to use.
  3735. //
  3736. CachedRights->NextInsert = Index + 1;
  3737. break;
  3738. }
  3739. }
  3740. //
  3741. // If the entry was not found above, add the new entry into the cache.
  3742. //
  3743. if (Index == CachedRights->Count) {
  3744. if ((CachedRights->Count >= 1) &&
  3745. !CachedRights->HaveEveryoneRights) {
  3746. //
  3747. // Once we add the second TokenId to the cache, we have a
  3748. // good indicator that having the world rights could be
  3749. // useful.
  3750. //
  3751. GetEveryoneRights = TRUE;
  3752. //
  3753. // Set the indicator that we have the rights now so that
  3754. // there is no need in the acquisition routine to acquire
  3755. // the security mutex. This will prevent multiple threads
  3756. // from attempting to acquire the everyone rights.
  3757. //
  3758. // Note that until we actually acquire the rights information
  3759. // caller will assume that the rights are 0 and go through
  3760. // the normal per-token access check path.
  3761. //
  3762. CachedRights->HaveEveryoneRights = TRUE;
  3763. }
  3764. Index = CachedRights->NextInsert;
  3765. //
  3766. // We will just replace the first entry in the list.
  3767. //
  3768. if (Index == NTFS_MAX_CACHED_RIGHTS) {
  3769. Index = 0;
  3770. }
  3771. ASSERT( Index < NTFS_MAX_CACHED_RIGHTS );
  3772. //
  3773. // Copy in the information.
  3774. //
  3775. CachedRights->TokenRights[Index].Rights = Rights;
  3776. RtlCopyLuid( &CachedRights->TokenRights[Index].TokenId,
  3777. TokenId );
  3778. RtlCopyLuid( &CachedRights->TokenRights[Index].ModifiedId,
  3779. ModifiedId );
  3780. if (Index == CachedRights->Count) {
  3781. //
  3782. // Bump the count of entries.
  3783. //
  3784. CachedRights->Count += 1;
  3785. }
  3786. //
  3787. // Remember the next entry to use.
  3788. //
  3789. CachedRights->NextInsert = Index + 1;
  3790. }
  3791. } finally {
  3792. NtfsReleaseFcbSecurity( Vcb );
  3793. }
  3794. if (GetEveryoneRights) {
  3795. NtfsSetCachedRightsWorld( SharedSecurity );
  3796. }
  3797. DebugTrace( -1, Dbg, ("NtfsAddCachedRights -> VOID\n") );
  3798. return;
  3799. }
  3800. #endif