/*++ Copyright (c) 2014 Minoca Corp. All Rights Reserved Module Name: perm.c Abstract: This module handles permission and access rights management in the I/O subsystem. Author: Evan Green 10-Dec-2014 Environment: Kernel --*/ // // ------------------------------------------------------------------- Includes // #include #include "iop.h" // // ---------------------------------------------------------------- Definitions // // // ------------------------------------------------------ Data Type Definitions // // // ----------------------------------------------- Internal Function Prototypes // // // -------------------------------------------------------------------- Globals // // // Set this to TRUE to break whenever access denied is returned. // BOOL IoBreakOnAccessDenied = FALSE; // // ------------------------------------------------------------------ Functions // KSTATUS IopCheckPermissions ( BOOL FromKernelMode, PPATH_POINT PathPoint, ULONG Access ) /*++ Routine Description: This routine performs a permission check for the current user at the given path point. Arguments: FromKernelMode - Supplies a boolean indicating whether the request actually originates from kernel mode or not. PathPoint - Supplies a pointer to the path point to check. Access - Supplies the desired access the user needs. Return Value: STATUS_SUCCESS if the user has permission to access the given object in the requested way. STATUS_ACCESS_DENIED if the permission was not granted. --*/ { PFILE_OBJECT FileObject; ULONG Rights; KSTATUS Status; PKTHREAD Thread; Thread = KeGetCurrentThread(); FileObject = PathPoint->PathEntry->FileObject; Rights = 0; // // If the caller wants execute permissions and none of the execute bits are // set, then even fancy override permissions can't make it succeed. This // doesn't apply to directories. // if ((FileObject->Properties.Type != IoObjectRegularDirectory) && (FileObject->Properties.Type != IoObjectObjectDirectory)) { if (((Access & IO_ACCESS_EXECUTE) != 0) && ((FileObject->Properties.Permissions & FILE_PERMISSION_ALL_EXECUTE) == 0)) { if (IoBreakOnAccessDenied != FALSE) { RtlDebugBreak(); } Status = STATUS_ACCESS_DENIED; goto CheckPermissionsEnd; } } // // If this is kernel mode, then none of the other checks apply. // if (FromKernelMode != FALSE) { Status = STATUS_SUCCESS; goto CheckPermissionsEnd; } // // Determine whether to use the access bits of the user, group, or other. // Rights = FileObject->Properties.Permissions >> FILE_PERMISSION_OTHER_SHIFT; if (FileObject->Properties.UserId == Thread->Identity.EffectiveUserId) { Rights = FileObject->Properties.Permissions >> FILE_PERMISSION_USER_SHIFT; } else if (PsIsUserInGroup(FileObject->Properties.GroupId) != FALSE) { Rights = FileObject->Properties.Permissions >> FILE_PERMISSION_GROUP_SHIFT; } // // Check the rights. Exit out if they succeed on their own. // if ((Rights & Access & FILE_PERMISSION_ACCESS_MASK) == Access) { Status = STATUS_SUCCESS; goto CheckPermissionsEnd; } // // Succeed and exit if the user has file system override permissions. // if (KSUCCESS(PsCheckPermission(PERMISSION_FILE_ACCESS))) { Status = STATUS_SUCCESS; goto CheckPermissionsEnd; } // // If the user has the read/search permission, then succeed for: // 1) Read permissions on anything. // 2) Read/execute permissions on directories. // if (KSUCCESS(PsCheckPermission(PERMISSION_READ_SEARCH))) { if (Access == IO_ACCESS_READ) { Status = STATUS_SUCCESS; goto CheckPermissionsEnd; } if (((Access & IO_ACCESS_WRITE) == 0) && ((FileObject->Properties.Type == IoObjectRegularDirectory) || (FileObject->Properties.Type == IoObjectObjectDirectory))) { Status = STATUS_SUCCESS; goto CheckPermissionsEnd; } } // // Sorry, no access this time. // if (IoBreakOnAccessDenied != FALSE) { RtlDebugBreak(); } Status = STATUS_ACCESS_DENIED; CheckPermissionsEnd: return Status; } KSTATUS IopCheckDeletePermission ( BOOL FromKernelMode, PPATH_POINT DirectoryPathPoint, PPATH_POINT FilePathPoint ) /*++ Routine Description: This routine performs a permission check for the current user at the given path point, in preparation for removing a directory entry during a rename or unlink operation. Arguments: FromKernelMode - Supplies a boolean indicating whether or not this request actually originated from kernel mode. DirectoryPathPoint - Supplies a pointer to the directory path point the file resides in. FilePathPoint - Supplies a pointer to the file path point being deleted or renamed. Return Value: STATUS_SUCCESS if the user has permission to access the given object in the requested way. STATUS_ACCESS_DENIED if the permission was not granted. --*/ { PFILE_OBJECT DirectoryFileObject; PFILE_OBJECT FileObject; KSTATUS Status; PKTHREAD Thread; Thread = KeGetCurrentThread(); DirectoryFileObject = DirectoryPathPoint->PathEntry->FileObject; // // First ensure the caller has write access to the directory. // Status = IopCheckPermissions(FromKernelMode, DirectoryPathPoint, IO_ACCESS_WRITE); if (!KSUCCESS(Status)) { goto CheckDeletePermissionEnd; } // // If the restricted bit is set, then only the file owner can rename or // delete the file, even though the caller has write permission in the // directory. This is often used on temporary directories to prevent users // from deleting each others files. // if ((DirectoryFileObject->Properties.Permissions & FILE_PERMISSION_RESTRICTED) != 0) { FileObject = FilePathPoint->PathEntry->FileObject; if (Thread->Identity.EffectiveUserId != FileObject->Properties.UserId) { if (!KSUCCESS(PsCheckPermission(PERMISSION_FILE_ACCESS))) { Status = STATUS_ACCESS_DENIED; goto CheckDeletePermissionEnd; } } } Status = STATUS_SUCCESS; CheckDeletePermissionEnd: return Status; } // // --------------------------------------------------------- Internal Functions //