|
|
/*++
Copyright (c) 1989-2000 Microsoft Corporation
Module Name:
AcChkSup.c
Abstract:
This module implements the FAT access checking routine
// @@BEGIN_DDKSPLIT
Author:
Gary Kimura [GaryKi] 12-Jun-1989
Revision History:
// @@END_DDKSPLIT
--*/
#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;
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; } finally {
DebugUnwind( FatCheckFileAccess );
DebugTrace(-1, Dbg, "FatCheckFileAccess -> %08lx\n", Result); }
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; BOOLEAN Result;
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;
Result = SeAccessCheck( DeviceObject->SecurityDescriptor, &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; }
|