3 Copyright (c) 1989-2000 Microsoft Corporation
11 This module implements the FAT access checking routine
19 // Our debug trace level
22 #define Dbg (DEBUG_TRACE_ACCHKSUP)
25 FatCreateRestrictEveryoneToken(
26 IN PACCESS_TOKEN Token
,
27 OUT PACCESS_TOKEN
*RestrictedToken
31 #pragma alloc_text(PAGE, FatCheckFileAccess)
32 #pragma alloc_text(PAGE, FatCheckManageVolumeAccess)
33 #pragma alloc_text(PAGE, FatCreateRestrictEveryoneToken)
34 #pragma alloc_text(PAGE, FatExplicitDeviceAccessGranted)
40 PIRP_CONTEXT IrpContext
,
41 IN UCHAR DirentAttributes
,
42 IN PACCESS_MASK DesiredAccess
49 This routine checks if a desired access is allowed to a file represented
50 by the specified DirentAttriubutes.
54 DirentAttributes - Supplies the Dirent attributes to check access for
56 DesiredAccess - Supplies the desired access mask that we are checking for
60 BOOLEAN - TRUE if access is allowed and FALSE otherwise
67 DebugTrace(+1, Dbg
, "FatCheckFileAccess\n", 0);
68 DebugTrace( 0, Dbg
, "DirentAttributes = %8lx\n", DirentAttributes
);
69 DebugTrace( 0, Dbg
, "DesiredAccess = %8lx\n", *DesiredAccess
);
74 // This procedures is programmed like a string of filters each
75 // filter checks to see if some access is allowed, if it is not allowed
76 // the filter return FALSE to the user without further checks otherwise
77 // it moves on to the next filter. The filter check is to check for
78 // desired access flags that are not allowed for a particular dirent
86 // Check for Volume ID or Device Dirents, these are not allowed user
90 if (FlagOn(DirentAttributes
, FAT_DIRENT_ATTR_VOLUME_ID
) ||
91 FlagOn(DirentAttributes
, FAT_DIRENT_ATTR_DEVICE
)) {
93 DebugTrace(0, Dbg
, "Cannot access volume id or device\n", 0);
95 try_return( Result
= FALSE
);
99 // Check the desired access for the object - we only blackball that
100 // we do not understand. The model of filesystems using ACLs is that
101 // they do not type the ACL to the object the ACL is on. Permissions
102 // are not checked for consistency vs. the object type - dir/file.
105 if (FlagOn(*DesiredAccess
, ~(DELETE
|
110 ACCESS_SYSTEM_SECURITY
|
114 FILE_READ_ATTRIBUTES
|
115 FILE_WRITE_ATTRIBUTES
|
116 FILE_LIST_DIRECTORY
|
122 DebugTrace(0, Dbg
, "Cannot open object\n", 0);
124 try_return( Result
= FALSE
);
128 // Check for a read-only Dirent
131 if (FlagOn(DirentAttributes
, FAT_DIRENT_ATTR_READ_ONLY
)) {
134 // Check the desired access for a read-only dirent. AccessMask will contain
135 // the flags we're going to allow.
138 ACCESS_MASK AccessMask
= DELETE
| READ_CONTROL
| WRITE_OWNER
| WRITE_DAC
|
139 SYNCHRONIZE
| ACCESS_SYSTEM_SECURITY
| FILE_READ_DATA
|
140 FILE_READ_EA
| FILE_WRITE_EA
| FILE_READ_ATTRIBUTES
|
141 FILE_WRITE_ATTRIBUTES
| FILE_EXECUTE
| FILE_LIST_DIRECTORY
|
145 // If this is a subdirectory also allow add file/directory and delete.
148 if (FlagOn(DirentAttributes
, FAT_DIRENT_ATTR_DIRECTORY
)) {
150 AccessMask
|= FILE_ADD_SUBDIRECTORY
| FILE_ADD_FILE
| FILE_DELETE_CHILD
;
153 if (FlagOn(*DesiredAccess
, ~AccessMask
)) {
155 DebugTrace(0, Dbg
, "Cannot open readonly\n", 0);
157 try_return( Result
= FALSE
);
164 DebugUnwind( FatCheckFileAccess
);
166 DebugTrace(-1, Dbg
, "FatCheckFileAccess -> %08lx\n", Result
);
169 UNREFERENCED_PARAMETER( IrpContext
);
176 FatCheckManageVolumeAccess (
177 _In_ PIRP_CONTEXT IrpContext
,
178 _In_ PACCESS_STATE AccessState
,
179 _In_ KPROCESSOR_MODE ProcessorMode
186 This function checks whether the SID described in the input access state has
187 manage volume privilege.
191 AccessState - the access state describing the security context to be checked
193 ProcessorMode - the mode this check should occur against
197 BOOLEAN - TRUE if privilege is held and FALSE otherwise
202 PRIVILEGE_SET PrivilegeSet
;
206 PrivilegeSet
.PrivilegeCount
= 1;
207 PrivilegeSet
.Control
= PRIVILEGE_SET_ALL_NECESSARY
;
208 PrivilegeSet
.Privilege
[0].Luid
= RtlConvertLongToLuid( SE_MANAGE_VOLUME_PRIVILEGE
);
209 PrivilegeSet
.Privilege
[0].Attributes
= 0;
211 if (SePrivilegeCheck( &PrivilegeSet
,
212 &AccessState
->SubjectSecurityContext
,
218 UNREFERENCED_PARAMETER( IrpContext
);
225 FatExplicitDeviceAccessGranted (
226 IN PIRP_CONTEXT IrpContext
,
227 IN PDEVICE_OBJECT DeviceObject
,
228 IN PACCESS_STATE AccessState
,
229 IN KPROCESSOR_MODE ProcessorMode
236 This function asks whether the SID described in the input access state has
237 been granted any explicit access to the given device object. It does this
238 by acquiring a token stripped of its ability to acquire access via the
239 Everyone SID and re-doing the access check.
243 DeviceObject - the device whose ACL will be checked
245 AccessState - the access state describing the security context to be checked
247 ProcessorMode - the mode this check should occur against
251 NTSTATUS - Indicating whether explicit access was granted.
258 PACCESS_TOKEN OriginalAccessToken
;
259 PACCESS_TOKEN RestrictedAccessToken
;
261 PACCESS_TOKEN
*EffectiveToken
;
263 ACCESS_MASK GrantedAccess
;
267 UNREFERENCED_PARAMETER( IrpContext
);
270 // If the access state indicates that specific access other
271 // than traverse was acquired, either Everyone does have such
272 // access or explicit access was granted. In both cases, we're
273 // happy to let this proceed.
276 if (AccessState
->PreviouslyGrantedAccess
& (SPECIFIC_RIGHTS_ALL
^
279 return STATUS_SUCCESS
;
283 // If the manage volume privilege is held, this also permits access.
286 if (FatCheckManageVolumeAccess( IrpContext
,
290 return STATUS_SUCCESS
;
294 // Capture the subject context as a prelude to everything below.
297 SeLockSubjectContext( &AccessState
->SubjectSecurityContext
);
300 // Convert the token in the subject context into one which does not
301 // acquire access through the Everyone SID.
303 // The logic for deciding which token is effective comes from
304 // SeQuerySubjectContextToken; since there is no natural way
305 // of getting a pointer to it, do it by hand.
308 if (ARGUMENT_PRESENT( AccessState
->SubjectSecurityContext
.ClientToken
)) {
309 EffectiveToken
= &AccessState
->SubjectSecurityContext
.ClientToken
;
311 EffectiveToken
= &AccessState
->SubjectSecurityContext
.PrimaryToken
;
314 OriginalAccessToken
= *EffectiveToken
;
315 Status
= FatCreateRestrictEveryoneToken( OriginalAccessToken
, &RestrictedAccessToken
);
317 if (!NT_SUCCESS(Status
)) {
319 SeReleaseSubjectContext( &AccessState
->SubjectSecurityContext
);
324 // Now see if the resulting context has access to the device through
325 // its explicitly granted access. We swap in our restricted token
326 // for this check as the effective client token.
329 *EffectiveToken
= RestrictedAccessToken
;
332 #pragma prefast( suppress: 28175, "we're a file system, this is ok to touch" )
334 SeAccessCheck( DeviceObject
->SecurityDescriptor
,
335 &AccessState
->SubjectSecurityContext
,
337 AccessState
->OriginalDesiredAccess
,
340 IoGetFileObjectGenericMapping(),
345 *EffectiveToken
= OriginalAccessToken
;
348 // Cleanup and return.
351 SeUnlockSubjectContext( &AccessState
->SubjectSecurityContext
);
352 ObDereferenceObject( RestrictedAccessToken
);
359 FatCreateRestrictEveryoneToken (
360 IN PACCESS_TOKEN Token
,
361 OUT PACCESS_TOKEN
*RestrictedToken
368 This function takes a token as the input and returns a new restricted token
369 from which Everyone sid has been disabled. The resulting token may be used
370 to find out if access is available to a user-sid by explicit means.
374 Token - Input token from which Everyone sid needs to be deactivated.
376 RestrictedToken - Receives the the new restricted token.
377 This must be released using ObDereferenceObject(*RestrictedToken);
381 NTSTATUS - Returned by SeFilterToken.
387 // Array of sids to disable.
390 TOKEN_GROUPS SidsToDisable
;
392 NTSTATUS Status
= STATUS_SUCCESS
;
397 // Restricted token will contain the original sids with one change:
398 // If Everyone sid is present in the token, it will be marked for DenyOnly.
401 *RestrictedToken
= NULL
;
404 // Put Everyone sid in the array of sids to disable. This will mark it
405 // for SE_GROUP_USE_FOR_DENY_ONLY and it'll only be applicable for Deny aces.
408 SidsToDisable
.GroupCount
= 1;
409 SidsToDisable
.Groups
[0].Attributes
= 0;
410 SidsToDisable
.Groups
[0].Sid
= SeExports
->SeWorldSid
;
412 Status
= SeFilterToken(
413 Token
, // Token that needs to be restricted.
415 &SidsToDisable
, // Disable everyone sid
416 NULL
, // Do not create any restricted sids
417 NULL
, // Do not delete any privileges
418 RestrictedToken
// Restricted token