reactos/drivers/filesystems/fastfat_new/acchksup.c
Pierre Schweitzer aeadcaf515
[FASTFAT] Import the MS FastFAT sample from WXP.
Modified it so that it builds in trunk (with GCC, though).
Not to be switched for now, as it doesn't work in ReactOS (yet?).
2017-11-23 12:35:51 +01:00

375 lines
10 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1989-2000 Microsoft Corporation
Module Name:
AcChkSup.c
Abstract:
This module implements the FAT access checking routine
--*/
#include "fatprocs.h"
//
// Our debug trace level
//
#define Dbg (DEBUG_TRACE_ACCHKSUP)
NTSTATUS
FatCreateRestrictEveryoneToken(
IN PACCESS_TOKEN Token,
OUT PACCESS_TOKEN *RestrictedToken
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, FatCheckFileAccess)
#pragma alloc_text(PAGE, FatCreateRestrictEveryoneToken)
#pragma alloc_text(PAGE, FatExplicitDeviceAccessGranted)
#endif
BOOLEAN
FatCheckFileAccess (
PIRP_CONTEXT IrpContext,
IN UCHAR DirentAttributes,
IN PACCESS_MASK DesiredAccess
)
/*++
Routine Description:
This routine checks if a desired access is allowed to a file represented
by the specified DirentAttriubutes.
Arguments:
DirentAttributes - Supplies the Dirent attributes to check access for
DesiredAccess - Supplies the desired access mask that we are checking for
Return Value:
BOOLEAN - TRUE if access is allowed and FALSE otherwise
--*/
{
BOOLEAN Result;
DebugTrace(+1, Dbg, "FatCheckFileAccess\n", 0);
DebugTrace( 0, Dbg, "DirentAttributes = %8lx\n", DirentAttributes);
DebugTrace( 0, Dbg, "DesiredAccess = %8lx\n", *DesiredAccess);
//
// This procedures is programmed like a string of filters each
// filter checks to see if some access is allowed, if it is not allowed
// the filter return FALSE to the user without further checks otherwise
// it moves on to the next filter. The filter check is to check for
// desired access flags that are not allowed for a particular dirent
//
Result = TRUE;
_SEH2_TRY {
//
// Check for Volume ID or Device Dirents, these are not allowed user
// access at all
//
if (FlagOn(DirentAttributes, FAT_DIRENT_ATTR_VOLUME_ID) ||
FlagOn(DirentAttributes, FAT_DIRENT_ATTR_DEVICE)) {
DebugTrace(0, Dbg, "Cannot access volume id or device\n", 0);
try_return( Result = FALSE );
}
//
// Check the desired access for the object - we only blackball that
// we do not understand. The model of filesystems using ACLs is that
// they do not type the ACL to the object the ACL is on. Permissions
// are not checked for consistency vs. the object type - dir/file.
//
if (FlagOn(*DesiredAccess, ~(DELETE |
READ_CONTROL |
WRITE_OWNER |
WRITE_DAC |
SYNCHRONIZE |
ACCESS_SYSTEM_SECURITY |
FILE_WRITE_DATA |
FILE_READ_EA |
FILE_WRITE_EA |
FILE_READ_ATTRIBUTES |
FILE_WRITE_ATTRIBUTES |
FILE_LIST_DIRECTORY |
FILE_TRAVERSE |
FILE_DELETE_CHILD |
FILE_APPEND_DATA))) {
DebugTrace(0, Dbg, "Cannot open object\n", 0);
try_return( Result = FALSE );
}
//
// Check for a read-only Dirent
//
if (FlagOn(DirentAttributes, FAT_DIRENT_ATTR_READ_ONLY)) {
//
// Check the desired access for a read-only dirent, we blackball
// WRITE, FILE_APPEND_DATA, FILE_ADD_FILE,
// FILE_ADD_SUBDIRECTORY, and FILE_DELETE_CHILD
//
if (FlagOn(*DesiredAccess, ~(DELETE |
READ_CONTROL |
WRITE_OWNER |
WRITE_DAC |
SYNCHRONIZE |
ACCESS_SYSTEM_SECURITY |
FILE_READ_DATA |
FILE_READ_EA |
FILE_WRITE_EA |
FILE_READ_ATTRIBUTES |
FILE_WRITE_ATTRIBUTES |
FILE_EXECUTE |
FILE_LIST_DIRECTORY |
FILE_TRAVERSE))) {
DebugTrace(0, Dbg, "Cannot open readonly\n", 0);
try_return( Result = FALSE );
}
}
try_exit: NOTHING;
} _SEH2_FINALLY {
DebugUnwind( FatCheckFileAccess );
DebugTrace(-1, Dbg, "FatCheckFileAccess -> %08lx\n", Result);
} _SEH2_END;
UNREFERENCED_PARAMETER( IrpContext );
return Result;
}
NTSTATUS
FatExplicitDeviceAccessGranted (
IN PIRP_CONTEXT IrpContext,
IN PDEVICE_OBJECT DeviceObject,
IN PACCESS_STATE AccessState,
IN KPROCESSOR_MODE ProcessorMode
)
/*++
Routine Description:
This function asks whether the SID described in the input access state has
been granted any explicit access to the given device object. It does this
by acquiring a token stripped of its ability to acquire access via the
Everyone SID and re-doing the access check.
Arguments:
DeviceObject - the device whose ACL will be checked
AccessState - the access state describing the security context to be checked
ProcessorMode - the mode this check should occur against
Return Value:
NTSTATUS - Indicating whether explicit access was granted.
--*/
{
NTSTATUS Status;
#ifndef __REACTOS__
BOOLEAN Result;
#endif
PACCESS_TOKEN OriginalAccessToken;
PACCESS_TOKEN RestrictedAccessToken;
PACCESS_TOKEN *EffectiveToken;
PRIVILEGE_SET PrivilegeSet;
ACCESS_MASK GrantedAccess;
//
// If the access state indicates that specific access other
// than traverse was acquired, either Everyone does have such
// access or explicit access was granted. In both cases, we're
// happy to let this proceed.
//
if (AccessState->PreviouslyGrantedAccess & (SPECIFIC_RIGHTS_ALL ^
FILE_TRAVERSE)) {
return STATUS_SUCCESS;
}
//
// If the manage volume privilege is held, this also permits access.
//
PrivilegeSet.PrivilegeCount = 1;
PrivilegeSet.Control = PRIVILEGE_SET_ALL_NECESSARY;
PrivilegeSet.Privilege[0].Luid = RtlConvertLongToLuid( SE_MANAGE_VOLUME_PRIVILEGE );
PrivilegeSet.Privilege[0].Attributes = 0;
if (SePrivilegeCheck( &PrivilegeSet,
&AccessState->SubjectSecurityContext,
ProcessorMode )) {
return STATUS_SUCCESS;
}
//
// Capture the subject context as a prelude to everything below.
//
SeLockSubjectContext( &AccessState->SubjectSecurityContext );
//
// Convert the token in the subject context into one which does not
// acquire access through the Everyone SID.
//
// The logic for deciding which token is effective comes from
// SeQuerySubjectContextToken; since there is no natural way
// of getting a pointer to it, do it by hand.
//
if (ARGUMENT_PRESENT( AccessState->SubjectSecurityContext.ClientToken )) {
EffectiveToken = &AccessState->SubjectSecurityContext.ClientToken;
} else {
EffectiveToken = &AccessState->SubjectSecurityContext.PrimaryToken;
}
OriginalAccessToken = *EffectiveToken;
Status = FatCreateRestrictEveryoneToken( OriginalAccessToken, &RestrictedAccessToken );
if (!NT_SUCCESS(Status)) {
SeReleaseSubjectContext( &AccessState->SubjectSecurityContext );
return Status;
}
//
// Now see if the resulting context has access to the device through
// its explicitly granted access. We swap in our restricted token
// for this check as the effective client token.
//
*EffectiveToken = RestrictedAccessToken;
#ifndef __REACTOS__
Result = SeAccessCheck( DeviceObject->SecurityDescriptor,
#else
SeAccessCheck( DeviceObject->SecurityDescriptor,
#endif
&AccessState->SubjectSecurityContext,
FALSE,
AccessState->OriginalDesiredAccess,
0,
NULL,
IoGetFileObjectGenericMapping(),
ProcessorMode,
&GrantedAccess,
&Status );
*EffectiveToken = OriginalAccessToken;
//
// Cleanup and return.
//
SeUnlockSubjectContext( &AccessState->SubjectSecurityContext );
ObDereferenceObject( RestrictedAccessToken );
return Status;
}
NTSTATUS
FatCreateRestrictEveryoneToken (
IN PACCESS_TOKEN Token,
OUT PACCESS_TOKEN *RestrictedToken
)
/*++
Routine Description:
This function takes a token as the input and returns a new restricted token
from which Everyone sid has been disabled. The resulting token may be used
to find out if access is available to a user-sid by explicit means.
Arguments:
Token - Input token from which Everyone sid needs to be deactivated.
RestrictedToken - Receives the the new restricted token.
This must be released using ObDereferenceObject(*RestrictedToken);
Return Value:
NTSTATUS - Returned by SeFilterToken.
--*/
{
//
// Array of sids to disable.
//
TOKEN_GROUPS SidsToDisable;
NTSTATUS Status = STATUS_SUCCESS;
//
// Restricted token will contain the original sids with one change:
// If Everyone sid is present in the token, it will be marked for DenyOnly.
//
*RestrictedToken = NULL;
//
// Put Everyone sid in the array of sids to disable. This will mark it
// for SE_GROUP_USE_FOR_DENY_ONLY and it'll only be applicable for Deny aces.
//
SidsToDisable.GroupCount = 1;
SidsToDisable.Groups[0].Attributes = 0;
SidsToDisable.Groups[0].Sid = SeExports->SeWorldSid;
Status = SeFilterToken(
Token, // Token that needs to be restricted.
0, // No flags
&SidsToDisable, // Disable everyone sid
NULL, // Do not create any restricted sids
NULL, // Do not delete any privileges
RestrictedToken // Restricted token
);
return Status;
}