📄 file.c
字号:
/*
* PROJECT: ReactOS Kernel
* LICENSE: GPL - See COPYING in the top level directory
* FILE: ntoskrnl/io/file.c
* PURPOSE: Functions that deal with managing the FILE_OBJECT itself.
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
* Gunnar Dalsnes
* Eric Kohl
* Filip Navara (navaraf@reactos.org)
*/
/* INCLUDES *****************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <debug.h>
/* PRIVATE FUNCTIONS *********************************************************/
VOID
NTAPI
IopCheckBackupRestorePrivilege(IN PACCESS_STATE AccessState,
IN OUT PULONG CreateOptions,
IN KPROCESSOR_MODE PreviousMode,
IN ULONG Disposition)
{
ACCESS_MASK DesiredAccess, ReadAccess, WriteAccess;
PRIVILEGE_SET Privileges;
BOOLEAN AccessGranted, HaveBackupPriv = FALSE, CheckRestore = FALSE;
PAGED_CODE();
/* Don't do anything if privileges were checked already */
if (AccessState->Flags & SE_BACKUP_PRIVILEGES_CHECKED) return;
/* Check if the file was actually opened for backup purposes */
if (*CreateOptions & FILE_OPEN_FOR_BACKUP_INTENT)
{
/* Set the check flag since were doing it now */
AccessState->Flags |= SE_BACKUP_PRIVILEGES_CHECKED;
/* Set the access masks required */
ReadAccess = READ_CONTROL |
ACCESS_SYSTEM_SECURITY |
FILE_GENERIC_READ |
FILE_TRAVERSE;
WriteAccess = WRITE_DAC |
WRITE_OWNER |
ACCESS_SYSTEM_SECURITY |
FILE_GENERIC_WRITE |
FILE_ADD_FILE |
FILE_ADD_SUBDIRECTORY |
DELETE;
DesiredAccess = AccessState->RemainingDesiredAccess;
/* Check if desired access was the maximum */
if (DesiredAccess & MAXIMUM_ALLOWED)
{
/* Then add all the access masks required */
DesiredAccess |= (ReadAccess | WriteAccess);
}
/* Check if the file already exists */
if (Disposition & FILE_OPEN)
{
/* Check if desired access has the read mask */
if (ReadAccess & DesiredAccess)
{
/* Setup the privilege check lookup */
Privileges.PrivilegeCount = 1;
Privileges.Control = PRIVILEGE_SET_ALL_NECESSARY;
Privileges.Privilege[0].Luid = SeBackupPrivilege;
Privileges.Privilege[0].Attributes = 0;
AccessGranted = SePrivilegeCheck(&Privileges,
&AccessState->
SubjectSecurityContext,
PreviousMode);
if (AccessGranted)
{
/* Remember that backup was allowed */
HaveBackupPriv = TRUE;
/* Append the privileges and update the access state */
SeAppendPrivileges(AccessState, &Privileges);
AccessState->PreviouslyGrantedAccess |= (DesiredAccess & ReadAccess);
AccessState->RemainingDesiredAccess &= ~ReadAccess;
DesiredAccess &= ~ReadAccess;
/* Set backup privilege for the token */
AccessState->Flags |= TOKEN_HAS_BACKUP_PRIVILEGE;
}
}
}
else
{
/* Caller is creating the file, check restore privileges later */
CheckRestore = TRUE;
}
/* Check if caller wants write access or if it's creating a file */
if ((WriteAccess & DesiredAccess) || (CheckRestore))
{
/* Setup the privilege lookup and do it */
Privileges.PrivilegeCount = 1;
Privileges.Control = PRIVILEGE_SET_ALL_NECESSARY;
Privileges.Privilege[0].Luid = SeRestorePrivilege;
Privileges.Privilege[0].Attributes = 0;
AccessGranted = SePrivilegeCheck(&Privileges,
&AccessState->SubjectSecurityContext,
PreviousMode);
if (AccessGranted)
{
/* Remember that privilege was given */
HaveBackupPriv = TRUE;
/* Append the privileges and update the access state */
SeAppendPrivileges(AccessState, &Privileges);
AccessState->PreviouslyGrantedAccess |= (DesiredAccess & WriteAccess);
AccessState->RemainingDesiredAccess &= ~WriteAccess;
/* Set restore privilege for the token */
AccessState->Flags |= TOKEN_HAS_RESTORE_PRIVILEGE;
}
}
/* If we don't have the privilege, remove the option */
if (!HaveBackupPriv) *CreateOptions &= ~FILE_OPEN_FOR_BACKUP_INTENT;
}
}
NTSTATUS
NTAPI
IopCheckDeviceAndDriver(IN POPEN_PACKET OpenPacket,
IN PDEVICE_OBJECT DeviceObject)
{
/* Make sure the object is valid */
if ((IoGetDevObjExtension(DeviceObject)->ExtensionFlags &
(DOE_UNLOAD_PENDING |
DOE_DELETE_PENDING |
DOE_REMOVE_PENDING |
DOE_REMOVE_PROCESSED)) ||
(DeviceObject->Flags & DO_DEVICE_INITIALIZING))
{
/* It's unloading or initializing, so fail */
DPRINT1("You are seeing this because the following ROS driver: %wZ\n"
" sucks. Please fix it's AddDevice Routine\n",
&DeviceObject->DriverObject->DriverName);
return STATUS_NO_SUCH_DEVICE;
}
else if ((DeviceObject->Flags & DO_EXCLUSIVE) &&
(DeviceObject->ReferenceCount) &&
!(OpenPacket->RelatedFileObject) &&
!(OpenPacket->Options & IO_ATTACH_DEVICE))
{
return STATUS_ACCESS_DENIED;
}
else
{
/* Increase reference count */
DeviceObject->ReferenceCount++;
return STATUS_SUCCESS;
}
}
NTSTATUS
NTAPI
IopParseDevice(IN PVOID ParseObject,
IN PVOID ObjectType,
IN OUT PACCESS_STATE AccessState,
IN KPROCESSOR_MODE AccessMode,
IN ULONG Attributes,
IN OUT PUNICODE_STRING CompleteName,
IN OUT PUNICODE_STRING RemainingName,
IN OUT PVOID Context OPTIONAL,
IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL,
OUT PVOID *Object)
{
POPEN_PACKET OpenPacket = (POPEN_PACKET)Context;
PDEVICE_OBJECT OriginalDeviceObject = (PDEVICE_OBJECT)ParseObject;
PDEVICE_OBJECT DeviceObject, OwnerDevice;
NTSTATUS Status;
PFILE_OBJECT FileObject;
PVPB Vpb = NULL;
PIRP Irp;
PEXTENDED_IO_STACK_LOCATION StackLoc;
IO_SECURITY_CONTEXT SecurityContext;
IO_STATUS_BLOCK IoStatusBlock;
BOOLEAN DirectOpen = FALSE, OpenCancelled, UseDummyFile;
OBJECT_ATTRIBUTES ObjectAttributes;
KIRQL OldIrql;
PDUMMY_FILE_OBJECT DummyFileObject;
PFILE_BASIC_INFORMATION FileBasicInfo;
ULONG ReturnLength;
KPROCESSOR_MODE CheckMode;
BOOLEAN VolumeOpen = FALSE;
ACCESS_MASK DesiredAccess, GrantedAccess;
BOOLEAN AccessGranted, LockHeld = FALSE;
PPRIVILEGE_SET Privileges = NULL;
IOTRACE(IO_FILE_DEBUG, "ParseObject: %p. RemainingName: %wZ\n",
ParseObject, RemainingName);
/* Assume failure */
*Object = NULL;
/* Validate the open packet */
if (!IopValidateOpenPacket(OpenPacket)) return STATUS_OBJECT_TYPE_MISMATCH;
/* Check if we have a related file object */
if (OpenPacket->RelatedFileObject)
{
/* Use the related file object's device object */
OriginalDeviceObject = OpenPacket->RelatedFileObject->DeviceObject;
}
/* Validate device status */
Status = IopCheckDeviceAndDriver(OpenPacket, OriginalDeviceObject);
if (!NT_SUCCESS(Status))
{
/* We failed, return status */
OpenPacket->FinalStatus = Status;
return Status;
}
/* Map the generic mask and set the new mapping in the access state */
RtlMapGenericMask(&AccessState->RemainingDesiredAccess,
&IoFileObjectType->TypeInfo.GenericMapping);
RtlMapGenericMask(&AccessState->OriginalDesiredAccess,
&IoFileObjectType->TypeInfo.GenericMapping);
SeSetAccessStateGenericMapping(AccessState,
&IoFileObjectType->TypeInfo.GenericMapping);
DesiredAccess = AccessState->RemainingDesiredAccess;
/* Check what kind of access checks to do */
if ((AccessMode != KernelMode) ||
(OpenPacket->Options & IO_FORCE_ACCESS_CHECK))
{
/* Call is from user-mode or kernel is forcing checks */
CheckMode = UserMode;
}
else
{
/* Call is from the kernel */
CheckMode = KernelMode;
}
/* Check privilege for backup or restore operation */
IopCheckBackupRestorePrivilege(AccessState,
&OpenPacket->CreateOptions,
CheckMode,
OpenPacket->Disposition);
/* Check if we are re-parsing */
if (((OpenPacket->Override) && !(RemainingName->Length)) ||
(AccessState->Flags & SE_BACKUP_PRIVILEGES_CHECKED))
{
/* Get granted access from the last call */
DesiredAccess |= AccessState->PreviouslyGrantedAccess;
}
/* Check if this is a volume open */
if ((OpenPacket->RelatedFileObject) &&
(OpenPacket->RelatedFileObject->Flags & FO_VOLUME_OPEN) &&
!(RemainingName->Length))
{
/* It is */
VolumeOpen = TRUE;
}
/* Now check if we need access checks */
if (((AccessMode != KernelMode) ||
(OpenPacket->Options & IO_FORCE_ACCESS_CHECK)) &&
(!(OpenPacket->RelatedFileObject) || (VolumeOpen)) &&
!(OpenPacket->Override))
{
/* Check if a device object is being parsed */
if (!RemainingName->Length)
{
/* Lock the subject context */
SeLockSubjectContext(&AccessState->SubjectSecurityContext);
LockHeld = TRUE;
/* Do access check */
AccessGranted = SeAccessCheck(OriginalDeviceObject->
SecurityDescriptor,
&AccessState->SubjectSecurityContext,
LockHeld,
DesiredAccess,
0,
&Privileges,
&IoFileObjectType->
TypeInfo.GenericMapping,
UserMode,
&GrantedAccess,
&Status);
if (Privileges)
{
/* Append and free the privileges */
SeAppendPrivileges(AccessState, Privileges);
SeFreePrivileges(Privileges);
}
/* Check if we got access */
if (AccessGranted)
{
/* Update access state */
AccessState->PreviouslyGrantedAccess |= GrantedAccess;
AccessState->RemainingDesiredAccess &= ~(GrantedAccess &
MAXIMUM_ALLOWED);
OpenPacket->Override= TRUE;
}
/* FIXME: Do Audit/Alarm for open operation */
}
else
{
/* Check if we need to do traverse validation */
if (!(AccessState->Flags & TOKEN_HAS_TRAVERSE_PRIVILEGE) ||
((OriginalDeviceObject->DeviceType == FILE_DEVICE_DISK) ||
(OriginalDeviceObject->DeviceType == FILE_DEVICE_CD_ROM)))
{
/* Check if this is a restricted token */
if (!(AccessState->Flags & TOKEN_IS_RESTRICTED))
{
/* FIXME: Do the FAST traverse check */
AccessGranted = FALSE;
}
else
{
/* Fail */
AccessGranted = FALSE;
}
/* Check if we failed to get access */
if (!AccessGranted)
{
/* Lock the subject context */
SeLockSubjectContext(&AccessState->SubjectSecurityContext);
LockHeld = TRUE;
/* Do access check */
AccessGranted = SeAccessCheck(OriginalDeviceObject->
SecurityDescriptor,
&AccessState->SubjectSecurityContext,
LockHeld,
FILE_TRAVERSE,
0,
&Privileges,
&IoFileObjectType->
TypeInfo.GenericMapping,
UserMode,
&GrantedAccess,
&Status);
if (Privileges)
{
/* Append and free the privileges */
SeAppendPrivileges(AccessState, Privileges);
SeFreePrivileges(Privileges);
}
}
/* FIXME: Do Audit/Alarm for traverse check */
}
else
{
/* Access automatically granted */
AccessGranted = TRUE;
}
}
/* Check if we hold the lock */
if (LockHeld)
{
/* Release it */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -