Sample Code

Windows Driver Samples/ fastfat File System Driver/ C++/ acchksup.c/

/*++

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, FatCheckManageVolumeAccess)
#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);

    PAGED_CODE();

    //
    //  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.  AccessMask will contain
            //  the flags we're going to allow.
            //

            ACCESS_MASK AccessMask = 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;

            //
            //  If this is a subdirectory also allow add file/directory and delete.
            //
            
            if (FlagOn(DirentAttributes, FAT_DIRENT_ATTR_DIRECTORY)) {

                AccessMask |= FILE_ADD_SUBDIRECTORY | FILE_ADD_FILE | FILE_DELETE_CHILD;
            }
            
            if (FlagOn(*DesiredAccess, ~AccessMask)) {

                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;
}


BOOLEAN
FatCheckManageVolumeAccess (
    _In_ PIRP_CONTEXT IrpContext,
    _In_ PACCESS_STATE AccessState,
    _In_ KPROCESSOR_MODE ProcessorMode
    )

/*++

Routine Description:

    This function checks whether the SID described in the input access state has
    manage volume privilege.

Arguments:

    AccessState - the access state describing the security context to be checked
    
    ProcessorMode - the mode this check should occur against

Return Value:

    BOOLEAN - TRUE if privilege is held and FALSE otherwise

--*/

{
    PRIVILEGE_SET PrivilegeSet;

    PAGED_CODE();

    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 TRUE;
    }

    UNREFERENCED_PARAMETER( IrpContext );

    return FALSE;
}


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;

    PACCESS_TOKEN OriginalAccessToken;
    PACCESS_TOKEN RestrictedAccessToken;
    
    PACCESS_TOKEN *EffectiveToken;
    
    ACCESS_MASK GrantedAccess;

    PAGED_CODE();

    UNREFERENCED_PARAMETER( IrpContext );

    //
    //  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.
    //

    if (FatCheckManageVolumeAccess( IrpContext,
                                    AccessState,
                                    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;
    
#pragma prefast( suppress: 28175, "we're a file system, this is ok to touch" )
    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;

    PAGED_CODE();

    //
    //  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;
}

Our Services

  • What our customers say about us?

© 2011-2024 All Rights Reserved. Joya Systems. 4425 South Mopac Building II Suite 101 Austin, TX 78735 Tel: 800-DEV-KERNEL

Privacy Policy. Terms of use. Valid XHTML & CSS