reactos/drivers/filesystems/udfs/secursup.cpp
2021-06-11 15:33:08 +03:00

1109 lines
33 KiB
C++

////////////////////////////////////////////////////////////////////
// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine
// All rights reserved
// This file was released under the GPLv2 on June 2015.
////////////////////////////////////////////////////////////////////
/*************************************************************************
*
* File: SecurSup.cpp
*
* Module: UDF File System Driver (Kernel mode execution only)
*
* Description:
* Contains code to handle the "Get/Set Security" dispatch entry points.
*
*************************************************************************/
#include "udffs.h"
// define the file specific bug-check id
#define UDF_BUG_CHECK_ID UDF_FILE_SECURITY
#ifdef UDF_ENABLE_SECURITY
NTSTATUS UDFConvertToSelfRelative(
IN OUT PSECURITY_DESCRIPTOR* SecurityDesc);
/*UCHAR FullControlSD[] = {
0x01, 0x00, 0x04, 0x80, 0x4c, 0x00, 0x00, 0x00,
0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x38, 0x00,
0x02, 0x00, 0x00, 0x00, 0x00, 0x09, 0x18, 0x00,
0x00, 0x00, 0x00, 0x10, 0x01, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x18, 0x00,
0xff, 0x01, 0x1f, 0x00, 0x01, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00
};*/
/*************************************************************************
*
* Function: UDFGetSecurity()
*
* Description:
*
* Expected Interrupt Level (for execution) :
*
* IRQL_PASSIVE_LEVEL
*
* Return Value: Irrelevant.
*
*************************************************************************/
NTSTATUS
UDFGetSecurity(
IN PDEVICE_OBJECT DeviceObject, // the logical volume device object
IN PIRP Irp) // I/O Request Packet
{
NTSTATUS RC = STATUS_SUCCESS;
PtrUDFIrpContext PtrIrpContext = NULL;
BOOLEAN AreWeTopLevel = FALSE;
UDFPrint(("UDFGetSecurity\n"));
// BrutePoint();
FsRtlEnterFileSystem();
ASSERT(DeviceObject);
ASSERT(Irp);
// set the top level context
AreWeTopLevel = UDFIsIrpTopLevel(Irp);
ASSERT(!UDFIsFSDevObj(DeviceObject));
// Call the common Lock Control routine, with blocking allowed if
// synchronous
_SEH2_TRY {
// get an IRP context structure and issue the request
PtrIrpContext = UDFAllocateIrpContext(Irp, DeviceObject);
if(PtrIrpContext) {
RC = UDFCommonGetSecurity(PtrIrpContext, Irp);
} else {
RC = STATUS_INSUFFICIENT_RESOURCES;
Irp->IoStatus.Status = RC;
Irp->IoStatus.Information = 0;
// complete the IRP
IoCompleteRequest(Irp, IO_DISK_INCREMENT);
}
} __except (UDFExceptionFilter(PtrIrpContext, GetExceptionInformation())) {
RC = UDFExceptionHandler(PtrIrpContext, Irp);
UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC);
}
if (AreWeTopLevel) {
IoSetTopLevelIrp(NULL);
}
FsRtlExitFileSystem();
return(RC);
} // end UDFGetSecurity()
/*************************************************************************
*
* Function: UDFCommonGetSecurity()
*
* Description:
* This is the common routine for getting Security (ACL) called
* by both the fsd and fsp threads
*
* Expected Interrupt Level (for execution) :
*
* IRQL_PASSIVE_LEVEL
*
* Return Value: Irrelevant
*
*************************************************************************/
NTSTATUS
UDFCommonGetSecurity(
IN PtrUDFIrpContext PtrIrpContext,
IN PIRP Irp)
{
NTSTATUS RC = STATUS_SUCCESS;
PIO_STACK_LOCATION IrpSp = NULL;
BOOLEAN PostRequest = FALSE;
BOOLEAN CanWait = FALSE;
PtrUDFNTRequiredFCB NtReqFcb = NULL;
BOOLEAN AcquiredFCB = FALSE;
PFILE_OBJECT FileObject = NULL;
PtrUDFFCB Fcb = NULL;
PtrUDFCCB Ccb = NULL;
PVOID PtrSystemBuffer = NULL;
ULONG BufferLength = 0;
UDFPrint(("UDFCommonGetSecurity\n"));
_SEH2_TRY {
// First, get a pointer to the current I/O stack location.
IrpSp = IoGetCurrentIrpStackLocation(Irp);
ASSERT(IrpSp);
FileObject = IrpSp->FileObject;
ASSERT(FileObject);
// Get the FCB and CCB pointers.
Ccb = (PtrUDFCCB)(FileObject->FsContext2);
ASSERT(Ccb);
Fcb = Ccb->Fcb;
ASSERT(Fcb);
/* if(!Fcb->Vcb->ReadSecurity)
try_return(RC = STATUS_NOT_IMPLEMENTED);*/
NtReqFcb = Fcb->NTRequiredFCB;
CanWait = ((PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE);
// Acquire the FCB resource shared
UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
if (!UDFAcquireResourceExclusive(&(NtReqFcb->MainResource), CanWait)) {
// if (!UDFAcquireResourceShared(&(NtReqFcb->MainResource), CanWait)) {
PostRequest = TRUE;
try_return(RC = STATUS_PENDING);
}
AcquiredFCB = TRUE;
PtrSystemBuffer = UDFGetCallersBuffer(PtrIrpContext, Irp);
if(!PtrSystemBuffer)
try_return(RC = STATUS_INVALID_USER_BUFFER);
BufferLength = IrpSp->Parameters.QuerySecurity.Length;
if(!NtReqFcb->SecurityDesc) {
RC = UDFAssignAcl(Fcb->Vcb, FileObject, Fcb, NtReqFcb);
if(!NT_SUCCESS(RC))
try_return(RC);
}
_SEH2_TRY {
RC = SeQuerySecurityDescriptorInfo(&(IrpSp->Parameters.QuerySecurity.SecurityInformation),
(PSECURITY_DESCRIPTOR)PtrSystemBuffer,
&BufferLength,
&(NtReqFcb->SecurityDesc) );
} _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
RC = STATUS_BUFFER_TOO_SMALL;
}
try_exit: NOTHING;
} _SEH2_FINALLY {
// Release the FCB resources if acquired.
if (AcquiredFCB) {
UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
UDFReleaseResource(&(NtReqFcb->MainResource));
AcquiredFCB = FALSE;
}
if (PostRequest) {
// Perform appropriate post related processing here
RC = UDFPostRequest(PtrIrpContext, Irp);
} else
if(!AbnormalTermination()) {
Irp->IoStatus.Status = RC;
Irp->IoStatus.Information = BufferLength;
// Free up the Irp Context
UDFReleaseIrpContext(PtrIrpContext);
// complete the IRP
IoCompleteRequest(Irp, IO_DISK_INCREMENT);
}
} // end of "__finally" processing
return(RC);
}
#ifndef UDF_READ_ONLY_BUILD
/*************************************************************************
*
* Function: UDFSetSecurity()
*
* Description:
*
* Expected Interrupt Level (for execution) :
*
* IRQL_PASSIVE_LEVEL
*
* Return Value: Irrelevant.
*
*************************************************************************/
NTSTATUS
UDFSetSecurity(
IN PDEVICE_OBJECT DeviceObject, // the logical volume device object
IN PIRP Irp) // I/O Request Packet
{
NTSTATUS RC = STATUS_SUCCESS;
PtrUDFIrpContext PtrIrpContext = NULL;
BOOLEAN AreWeTopLevel = FALSE;
UDFPrint(("UDFSetSecurity\n"));
// BrutePoint();
FsRtlEnterFileSystem();
ASSERT(DeviceObject);
ASSERT(Irp);
// set the top level context
AreWeTopLevel = UDFIsIrpTopLevel(Irp);
// Call the common Lock Control routine, with blocking allowed if
// synchronous
_SEH2_TRY {
// get an IRP context structure and issue the request
PtrIrpContext = UDFAllocateIrpContext(Irp, DeviceObject);
if(PtrIrpContext) {
RC = UDFCommonSetSecurity(PtrIrpContext, Irp);
} else {
RC = STATUS_INSUFFICIENT_RESOURCES;
Irp->IoStatus.Status = RC;
Irp->IoStatus.Information = 0;
// complete the IRP
IoCompleteRequest(Irp, IO_DISK_INCREMENT);
}
} __except (UDFExceptionFilter(PtrIrpContext, GetExceptionInformation())) {
RC = UDFExceptionHandler(PtrIrpContext, Irp);
UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC);
}
if (AreWeTopLevel) {
IoSetTopLevelIrp(NULL);
}
FsRtlExitFileSystem();
return(RC);
} // end UDFSetSecurity()
/*************************************************************************
*
* Function: UDFCommonSetSecurity()
*
* Description:
* This is the common routine for getting Security (ACL) called
* by both the fsd and fsp threads
*
* Expected Interrupt Level (for execution) :
*
* IRQL_PASSIVE_LEVEL
*
* Return Value: Irrelevant
*
*************************************************************************/
NTSTATUS
UDFCommonSetSecurity(
IN PtrUDFIrpContext PtrIrpContext,
IN PIRP Irp)
{
NTSTATUS RC = STATUS_SUCCESS;
PIO_STACK_LOCATION IrpSp = NULL;
BOOLEAN PostRequest = FALSE;
BOOLEAN CanWait = FALSE;
PtrUDFNTRequiredFCB NtReqFcb = NULL;
BOOLEAN AcquiredFCB = FALSE;
PFILE_OBJECT FileObject = NULL;
PtrUDFFCB Fcb = NULL;
PtrUDFCCB Ccb = NULL;
ACCESS_MASK DesiredAccess = 0;
UDFPrint(("UDFCommonSetSecurity\n"));
_SEH2_TRY {
// First, get a pointer to the current I/O stack location.
IrpSp = IoGetCurrentIrpStackLocation(Irp);
ASSERT(IrpSp);
FileObject = IrpSp->FileObject;
ASSERT(FileObject);
// Get the FCB and CCB pointers.
Ccb = (PtrUDFCCB)(FileObject->FsContext2);
ASSERT(Ccb);
Fcb = Ccb->Fcb;
ASSERT(Fcb);
if(!Fcb->Vcb->WriteSecurity)
try_return(RC = STATUS_NOT_IMPLEMENTED);
NtReqFcb = Fcb->NTRequiredFCB;
CanWait = ((PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE);
// Acquire the FCB resource exclusive
UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
if (!UDFAcquireResourceExclusive(&(NtReqFcb->MainResource), CanWait)) {
PostRequest = TRUE;
try_return(RC = STATUS_PENDING);
}
AcquiredFCB = TRUE;
//OWNER_SECURITY_INFORMATION
if(IrpSp->Parameters.SetSecurity.SecurityInformation & OWNER_SECURITY_INFORMATION)
DesiredAccess |= WRITE_OWNER;
//GROUP_SECURITY_INFORMATION
if(IrpSp->Parameters.SetSecurity.SecurityInformation & GROUP_SECURITY_INFORMATION)
DesiredAccess |= WRITE_OWNER;
//DACL_SECURITY_INFORMATION
if(IrpSp->Parameters.SetSecurity.SecurityInformation & DACL_SECURITY_INFORMATION)
DesiredAccess |= WRITE_DAC;
//SACL_SECURITY_INFORMATION
if(IrpSp->Parameters.SetSecurity.SecurityInformation & SACL_SECURITY_INFORMATION)
DesiredAccess |= ACCESS_SYSTEM_SECURITY;
_SEH2_TRY {
UDFConvertToSelfRelative(&(NtReqFcb->SecurityDesc));
KdDump(NtReqFcb->SecurityDesc, RtlLengthSecurityDescriptor(NtReqFcb->SecurityDesc));
UDFPrint(("\n"));
RC = SeSetSecurityDescriptorInfo(/*FileObject*/ NULL,
&(IrpSp->Parameters.SetSecurity.SecurityInformation),
IrpSp->Parameters.SetSecurity.SecurityDescriptor,
&(NtReqFcb->SecurityDesc),
NonPagedPool,
IoGetFileObjectGenericMapping() );
KdDump(NtReqFcb->SecurityDesc, RtlLengthSecurityDescriptor(NtReqFcb->SecurityDesc));
} _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
RC = STATUS_INVALID_PARAMETER;
}
if(NT_SUCCESS(RC)) {
NtReqFcb->NtReqFCBFlags |= UDF_NTREQ_FCB_SD_MODIFIED;
UDFNotifyFullReportChange( Fcb->Vcb, Fcb->FileInfo,
FILE_NOTIFY_CHANGE_SECURITY,
FILE_ACTION_MODIFIED);
}
try_exit: NOTHING;
} _SEH2_FINALLY {
// Release the FCB resources if acquired.
if (AcquiredFCB) {
UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
UDFReleaseResource(&(NtReqFcb->MainResource));
AcquiredFCB = FALSE;
}
if (PostRequest) {
// Perform appropriate post related processing here
RC = UDFPostRequest(PtrIrpContext, Irp);
} else
if(!AbnormalTermination()) {
Irp->IoStatus.Status = RC;
Irp->IoStatus.Information = 0;
// Free up the Irp Context
UDFReleaseIrpContext(PtrIrpContext);
// complete the IRP
IoCompleteRequest(Irp, IO_DISK_INCREMENT);
}
} // end of "__finally" processing
return(RC);
} // ens UDFCommonSetSecurity()
#endif //UDF_READ_ONLY_BUILD
#endif //UDF_ENABLE_SECURITY
NTSTATUS
UDFReadSecurity(
IN PVCB Vcb,
IN PtrUDFFCB Fcb,
IN PSECURITY_DESCRIPTOR* SecurityDesc
)
{
#ifdef UDF_ENABLE_SECURITY
PUDF_FILE_INFO FileInfo = NULL;
PUDF_FILE_INFO SDirInfo = NULL;
PUDF_FILE_INFO AclInfo = NULL;
NTSTATUS RC;
ULONG NumberBytesRead;
PERESOURCE Res1 = NULL;
UDFPrint(("UDFReadSecurity\n"));
_SEH2_TRY {
FileInfo = Fcb->FileInfo;
ASSERT(FileInfo);
if(!FileInfo) {
UDFPrint((" Volume Security\n"));
try_return(RC = STATUS_NO_SECURITY_ON_OBJECT);
}
if(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK) {
UDFPrint((" No Security on blank volume\n"));
try_return(RC = STATUS_NO_SECURITY_ON_OBJECT);
}
// Open Stream Directory
RC = UDFOpenStreamDir__(Vcb, FileInfo, &SDirInfo);
if(RC == STATUS_NOT_FOUND)
try_return(RC = STATUS_NO_SECURITY_ON_OBJECT);
if(!NT_SUCCESS(RC)) {
if(UDFCleanUpFile__(Vcb, SDirInfo)) {
if(SDirInfo) MyFreePool__(SDirInfo);
}
SDirInfo = NULL;
try_return(RC);
}
// Acquire SDir exclusively if Fcb present
if(SDirInfo->Fcb) {
BrutePoint();
UDF_CHECK_PAGING_IO_RESOURCE(SDirInfo->Fcb->NTRequiredFCB);
UDFAcquireResourceExclusive(Res1 = &(SDirInfo->Fcb->NTRequiredFCB->MainResource),TRUE);
}
// Open Acl Stream
RC = UDFOpenFile__(Vcb,
FALSE,TRUE,&(UDFGlobalData.AclName),
SDirInfo,&AclInfo,NULL);
if(RC == STATUS_OBJECT_NAME_NOT_FOUND)
try_return(RC = STATUS_NO_SECURITY_ON_OBJECT);
if(!NT_SUCCESS(RC)) {
if(UDFCleanUpFile__(Vcb, AclInfo)) {
if(AclInfo) MyFreePool__(AclInfo);
}
AclInfo = NULL;
try_return(RC);
}
NumberBytesRead = (ULONG)UDFGetFileSize(AclInfo);
(*SecurityDesc) = DbgAllocatePool(NonPagedPool, NumberBytesRead);
if(!(*SecurityDesc))
try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
RC = UDFReadFile__(Vcb, AclInfo, 0, NumberBytesRead,
FALSE, (PCHAR)(*SecurityDesc), &NumberBytesRead);
if(!NT_SUCCESS(RC))
try_return(RC);
RC = RtlValidSecurityDescriptor(*SecurityDesc);
try_exit: NOTHING;
} _SEH2_FINALLY {
if(AclInfo) {
UDFCloseFile__(Vcb, AclInfo);
if(UDFCleanUpFile__(Vcb, AclInfo))
MyFreePool__(AclInfo);
}
if(SDirInfo) {
UDFCloseFile__(Vcb, SDirInfo);
if(UDFCleanUpFile__(Vcb, SDirInfo))
MyFreePool__(SDirInfo);
}
if(!NT_SUCCESS(RC) && (*SecurityDesc)) {
DbgFreePool(*SecurityDesc);
(*SecurityDesc) = NULL;
}
if(Res1)
UDFReleaseResource(Res1);
}
return RC;
#else
return STATUS_NO_SECURITY_ON_OBJECT;
#endif //UDF_ENABLE_SECURITY
} // end UDFReadSecurity()
#ifdef UDF_ENABLE_SECURITY
NTSTATUS
UDFConvertToSelfRelative(
IN OUT PSECURITY_DESCRIPTOR* SecurityDesc
)
{
NTSTATUS RC;
SECURITY_INFORMATION SecurityInformation;
PSECURITY_DESCRIPTOR NewSD;
ULONG Len;
UDFPrint((" UDFConvertToSelfRelative\n"));
if(!(*SecurityDesc))
return STATUS_NO_SECURITY_ON_OBJECT;
SecurityInformation = FULL_SECURITY_INFORMATION;
Len = RtlLengthSecurityDescriptor(*SecurityDesc);
ASSERT(Len <= 1024);
NewSD = (PSECURITY_DESCRIPTOR)DbgAllocatePool(NonPagedPool, Len);
if(!NewSD)
return STATUS_INSUFFICIENT_RESOURCES;
_SEH2_TRY {
RC = SeQuerySecurityDescriptorInfo(&SecurityInformation, NewSD, &Len, SecurityDesc);
} _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
RC = STATUS_INSUFFICIENT_RESOURCES;
}
if(NT_SUCCESS(RC)) {
DbgFreePool(*SecurityDesc);
*SecurityDesc = NewSD;
} else {
DbgFreePool(NewSD);
}
return RC;
} // end UDFConvertToSelfRelative()
NTSTATUS
UDFInheritAcl(
IN PVCB Vcb,
IN PSECURITY_DESCRIPTOR* ParentSecurityDesc,
IN OUT PSECURITY_DESCRIPTOR* SecurityDesc
)
{
NTSTATUS RC;
SECURITY_INFORMATION SecurityInformation;
ULONG Len;
UDFPrint((" UDFInheritAcl\n"));
if(!(*ParentSecurityDesc)) {
*SecurityDesc = NULL;
return STATUS_SUCCESS;
}
SecurityInformation = FULL_SECURITY_INFORMATION;
Len = RtlLengthSecurityDescriptor(*ParentSecurityDesc);
*SecurityDesc = (PSECURITY_DESCRIPTOR)DbgAllocatePool(NonPagedPool, Len);
if(!(*SecurityDesc))
return STATUS_INSUFFICIENT_RESOURCES;
_SEH2_TRY {
RC = SeQuerySecurityDescriptorInfo(&SecurityInformation, *SecurityDesc, &Len, ParentSecurityDesc);
} _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
RC = STATUS_INSUFFICIENT_RESOURCES;
}
if(!NT_SUCCESS(RC)) {
DbgFreePool(*SecurityDesc);
*SecurityDesc = NULL;
}
return RC;
} // end UDFInheritAcl()
NTSTATUS
UDFBuildEmptyAcl(
IN PVCB Vcb,
IN PSECURITY_DESCRIPTOR* SecurityDesc
)
{
NTSTATUS RC;
ULONG Len = 2 * (sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) + sizeof(ULONG)*4 /*RtlLengthSid(SeExports->SeWorldSid)*/);
UDFPrint((" UDFBuildEmptyAcl\n"));
// Create Security Descriptor
(*SecurityDesc) = (PSECURITY_DESCRIPTOR)DbgAllocatePool(NonPagedPool,
sizeof(SECURITY_DESCRIPTOR) + Len);
if(!(*SecurityDesc))
return STATUS_INSUFFICIENT_RESOURCES;
RC = RtlCreateSecurityDescriptor(*SecurityDesc, SECURITY_DESCRIPTOR_REVISION);
if(!NT_SUCCESS(RC)) {
DbgFreePool(*SecurityDesc);
*((PULONG)SecurityDesc) = NULL;
}
return RC;
} // end UDFBuildEmptyAcl()
NTSTATUS
UDFBuildFullControlAcl(
IN PVCB Vcb,
IN PSECURITY_DESCRIPTOR* SecurityDesc
)
{
NTSTATUS RC;
PACL Acl;
ULONG Len = sizeof(ACL) + 2*(sizeof(ACCESS_ALLOWED_ACE) + sizeof(ULONG)*4 /*- sizeof(ULONG)*/ /*+ RtlLengthSid(SeExports->SeWorldSid)*/);
UDFPrint((" UDFBuildFullControlAcl\n"));
// Create Security Descriptor
RC = UDFBuildEmptyAcl(Vcb, SecurityDesc);
if(!NT_SUCCESS(RC))
return RC;
// Set Owner
RC = RtlSetOwnerSecurityDescriptor(*SecurityDesc, SeExports->SeWorldSid, FALSE);
if(!NT_SUCCESS(RC)) {
DbgFreePool(*SecurityDesc);
*((PULONG)SecurityDesc) = NULL;
return RC;
}
// Set Group
RC = RtlSetGroupSecurityDescriptor(*SecurityDesc, SeExports->SeWorldSid, FALSE);
if(!NT_SUCCESS(RC)) {
DbgFreePool(*SecurityDesc);
*((PULONG)SecurityDesc) = NULL;
return RC;
}
// Create empty Acl
Acl = (PACL)DbgAllocatePool(NonPagedPool, Len);
if(!Acl) {
DbgFreePool(*SecurityDesc);
*((PULONG)SecurityDesc) = NULL;
return RC;
}
RtlZeroMemory(Acl, Len);
RC = RtlCreateAcl(Acl, Len, ACL_REVISION);
if(!NT_SUCCESS(RC)) {
DbgFreePool(Acl);
DbgFreePool(*SecurityDesc);
*((PULONG)SecurityDesc) = NULL;
return RC;
}
// Add (All)(All) access for Everyone
/* RC = RtlAddAccessAllowedAce(Acl, ACL_REVISION,
GENERIC_ALL,
SeExports->SeWorldSid);*/
RC = RtlAddAccessAllowedAce(Acl, ACL_REVISION,
FILE_ALL_ACCESS,
SeExports->SeWorldSid);
if(!NT_SUCCESS(RC)) {
DbgFreePool(Acl);
DbgFreePool(*SecurityDesc);
*((PULONG)SecurityDesc) = NULL;
return RC;
}
// Add Acl to Security Descriptor
RC = RtlSetDaclSecurityDescriptor(*SecurityDesc, TRUE, Acl, FALSE);
if(!NT_SUCCESS(RC)) {
DbgFreePool(Acl);
DbgFreePool(*SecurityDesc);
*((PULONG)SecurityDesc) = NULL;
return RC;
}
RC = UDFConvertToSelfRelative(SecurityDesc);
DbgFreePool(Acl);
return RC;
} // end UDFBuildFullControlAcl()
#endif // UDF_ENABLE_SECURITY
NTSTATUS
UDFAssignAcl(
IN PVCB Vcb,
IN PFILE_OBJECT FileObject, // OPTIONAL
IN PtrUDFFCB Fcb,
IN PtrUDFNTRequiredFCB NtReqFcb
)
{
NTSTATUS RC = STATUS_SUCCESS;
#ifdef UDF_ENABLE_SECURITY
// SECURITY_INFORMATION SecurityInformation;
// UDFPrint((" UDFAssignAcl\n"));
if(!NtReqFcb->SecurityDesc) {
PSECURITY_DESCRIPTOR ExplicitSecurity = NULL;
if(UDFIsAStreamDir(Fcb->FileInfo) || UDFIsAStream(Fcb->FileInfo)) {
// Stream/SDir security
NtReqFcb->SecurityDesc = Fcb->FileInfo->ParentFile->Dloc->CommonFcb->SecurityDesc;
return STATUS_SUCCESS;
} else
if(!Fcb->FileInfo) {
// Volume security
if(Vcb->RootDirFCB &&
Vcb->RootDirFCB->FileInfo &&
Vcb->RootDirFCB->FileInfo->Dloc &&
Vcb->RootDirFCB->FileInfo->Dloc->CommonFcb) {
RC = UDFInheritAcl(Vcb, &(Vcb->RootDirFCB->FileInfo->Dloc->CommonFcb->SecurityDesc), &ExplicitSecurity);
} else {
NtReqFcb->SecurityDesc = NULL;
RC = STATUS_NO_SECURITY_ON_OBJECT;
}
return RC;
}
RC = UDFReadSecurity(Vcb, Fcb, &ExplicitSecurity);
if(RC == STATUS_NO_SECURITY_ON_OBJECT) {
if(!Fcb->FileInfo->ParentFile) {
RC = UDFBuildFullControlAcl(Vcb, &ExplicitSecurity);
} else {
RC = UDFInheritAcl(Vcb, &(Fcb->FileInfo->ParentFile->Dloc->CommonFcb->SecurityDesc), &ExplicitSecurity);
}
/* if(NT_SUCCESS(RC)) {
NtReqFcb->NtReqFCBFlags |= UDF_NTREQ_FCB_SD_MODIFIED;
}*/
}
if(NT_SUCCESS(RC)) {
// SecurityInformation = FULL_SECURITY_INFORMATION;
NtReqFcb->SecurityDesc = ExplicitSecurity;
/* RC = SeSetSecurityDescriptorInfo(FileObject,
&SecurityInformation,
ExplicitSecurity,
&(NtReqFcb->SecurityDesc),
NonPagedPool,
IoGetFileObjectGenericMapping() );*/
}
}
#endif //UDF_ENABLE_SECURITY
return RC;
} // end UDFAssignAcl()
VOID
UDFDeassignAcl(
IN PtrUDFNTRequiredFCB NtReqFcb,
IN BOOLEAN AutoInherited
)
{
#ifdef UDF_ENABLE_SECURITY
// NTSTATUS RC = STATUS_SUCCESS;
// UDFPrint((" UDFDeassignAcl\n"));
if(!NtReqFcb->SecurityDesc)
return;
if(AutoInherited) {
NtReqFcb->SecurityDesc = NULL;
return;
}
SeDeassignSecurity(&(NtReqFcb->SecurityDesc));
NtReqFcb->SecurityDesc = NULL; // HA BCRK CLU4
#endif //UDF_ENABLE_SECURITY
return;
} // end UDFDeassignAcl()
NTSTATUS
UDFWriteSecurity(
IN PVCB Vcb,
IN PtrUDFFCB Fcb,
IN PSECURITY_DESCRIPTOR* SecurityDesc
)
{
#ifdef UDF_ENABLE_SECURITY
PUDF_FILE_INFO FileInfo = NULL;
PUDF_FILE_INFO SDirInfo = NULL;
PUDF_FILE_INFO AclInfo = NULL;
PERESOURCE Res1 = NULL;
NTSTATUS RC;
ULONG NumberBytesRead;
// UDFPrint(("UDFWriteSecurity\n"));
#if !defined(UDF_READ_ONLY_BUILD)
if(!Vcb->WriteSecurity ||
(Vcb->VCBFlags & (UDF_VCB_FLAGS_VOLUME_READ_ONLY |
UDF_VCB_FLAGS_MEDIA_READ_ONLY)))
#endif //!defined(UDF_READ_ONLY_BUILD)
return STATUS_SUCCESS;
#if !defined(UDF_READ_ONLY_BUILD)
_SEH2_TRY {
FileInfo = Fcb->FileInfo;
ASSERT(FileInfo);
if(!FileInfo) {
UDFPrint((" Volume Security\n"));
try_return(RC = STATUS_SUCCESS);
}
if(!(Fcb->NTRequiredFCB->NtReqFCBFlags & UDF_NTREQ_FCB_SD_MODIFIED))
try_return(RC = STATUS_SUCCESS);
// Open Stream Directory
RC = UDFOpenStreamDir__(Vcb, FileInfo, &SDirInfo);
if(RC == STATUS_NOT_FOUND) {
RC = UDFCreateStreamDir__(Vcb, FileInfo, &SDirInfo);
}
if(!NT_SUCCESS(RC)) {
if(UDFCleanUpFile__(Vcb, SDirInfo)) {
if(SDirInfo) MyFreePool__(SDirInfo);
}
SDirInfo = NULL;
try_return(RC);
}
// Acquire SDir exclusively if Fcb present
if(SDirInfo->Fcb) {
BrutePoint();
UDF_CHECK_PAGING_IO_RESOURCE(SDirInfo->Fcb->NTRequiredFCB);
UDFAcquireResourceExclusive(Res1 = &(SDirInfo->Fcb->NTRequiredFCB->MainResource),TRUE);
}
// Open Acl Stream
RC = UDFOpenFile__(Vcb,
FALSE,TRUE,&(UDFGlobalData.AclName),
SDirInfo,&AclInfo,NULL);
if(RC == STATUS_OBJECT_NAME_NOT_FOUND) {
RC = UDFCreateFile__(Vcb, FALSE, &(UDFGlobalData.AclName),
0, 0, FALSE, FALSE, SDirInfo, &AclInfo);
}
if(!NT_SUCCESS(RC)) {
if(UDFCleanUpFile__(Vcb, AclInfo)) {
if(AclInfo) MyFreePool__(AclInfo);
}
AclInfo = NULL;
try_return(RC);
}
if(!(*SecurityDesc)) {
UDFFlushFile__(Vcb, AclInfo);
RC = UDFUnlinkFile__(Vcb, AclInfo, TRUE);
try_return(RC);
}
NumberBytesRead = RtlLengthSecurityDescriptor(*SecurityDesc);
RC = UDFWriteFile__(Vcb, AclInfo, 0, NumberBytesRead,
FALSE, (PCHAR)(*SecurityDesc), &NumberBytesRead);
if(!NT_SUCCESS(RC))
try_return(RC);
Fcb->NTRequiredFCB->NtReqFCBFlags &= ~UDF_NTREQ_FCB_SD_MODIFIED;
try_exit: NOTHING;
} _SEH2_FINALLY {
if(AclInfo) {
UDFCloseFile__(Vcb, AclInfo);
if(UDFCleanUpFile__(Vcb, AclInfo))
MyFreePool__(AclInfo);
}
if(SDirInfo) {
UDFCloseFile__(Vcb, SDirInfo);
if(UDFCleanUpFile__(Vcb, SDirInfo))
MyFreePool__(SDirInfo);
}
if(Res1)
UDFReleaseResource(Res1);
}
return RC;
#endif //!defined(UDF_READ_ONLY_BUILD)
#endif //UDF_ENABLE_SECURITY
return STATUS_SUCCESS;
} // end UDFWriteSecurity()
PSECURITY_DESCRIPTOR
UDFLookUpAcl(
IN PVCB Vcb,
PFILE_OBJECT FileObject, // OPTIONAL
IN PtrUDFFCB Fcb
)
{
UDFAssignAcl(Vcb, FileObject, Fcb, Fcb->NTRequiredFCB);
return (Fcb->NTRequiredFCB->SecurityDesc);
} // end UDFLookUpAcl()
NTSTATUS
UDFCheckAccessRights(
PFILE_OBJECT FileObject, // OPTIONAL
PACCESS_STATE AccessState,
PtrUDFFCB Fcb,
PtrUDFCCB Ccb, // OPTIONAL
ACCESS_MASK DesiredAccess,
USHORT ShareAccess
)
{
NTSTATUS RC;
BOOLEAN ROCheck = FALSE;
#ifdef UDF_ENABLE_SECURITY
BOOLEAN SecurityCheck;
PSECURITY_DESCRIPTOR SecDesc;
SECURITY_SUBJECT_CONTEXT SubjectContext;
ACCESS_MASK LocalAccessMask;
#endif //UDF_ENABLE_SECURITY
// Check attr compatibility
ASSERT(Fcb);
ASSERT(Fcb->Vcb);
#ifdef UDF_READ_ONLY_BUILD
goto treat_as_ro;
#endif //UDF_READ_ONLY_BUILD
if(Fcb->FCBFlags & UDF_FCB_READ_ONLY) {
ROCheck = TRUE;
} else
if((Fcb->Vcb->origIntegrityType == INTEGRITY_TYPE_OPEN) &&
Ccb && !(Ccb->CCBFlags & UDF_CCB_VOLUME_OPEN) &&
(Fcb->Vcb->CompatFlags & UDF_VCB_IC_DIRTY_RO)) {
AdPrint(("force R/O on dirty\n"));
ROCheck = TRUE;
}
if(ROCheck) {
#ifdef UDF_READ_ONLY_BUILD
treat_as_ro:
#endif //UDF_READ_ONLY_BUILD
ACCESS_MASK DesiredAccessMask = 0;
if(Fcb->Vcb->CompatFlags & UDF_VCB_IC_WRITE_IN_RO_DIR) {
if(Fcb->FCBFlags & UDF_FCB_DIRECTORY) {
DesiredAccessMask = (FILE_WRITE_EA |
DELETE);
} else {
DesiredAccessMask = (FILE_WRITE_DATA |
FILE_APPEND_DATA |
FILE_WRITE_EA |
DELETE);
}
} else {
DesiredAccessMask = (FILE_WRITE_DATA |
FILE_APPEND_DATA |
FILE_WRITE_EA |
FILE_DELETE_CHILD |
FILE_ADD_SUBDIRECTORY |
FILE_ADD_FILE |
DELETE);
}
if(DesiredAccess & DesiredAccessMask)
return STATUS_ACCESS_DENIED;
}
#ifdef UDF_ENABLE_SECURITY
// Check Security
// NOTE: we should not perform security check if an empty DesiredAccess
// was specified. AFAIU, SeAccessCheck() will return FALSE in this case.
SecDesc = UDFLookUpAcl(Fcb->Vcb, FileObject, Fcb);
if(SecDesc && DesiredAccess) {
SeCaptureSubjectContext(&SubjectContext);
SecurityCheck =
SeAccessCheck(SecDesc,
&SubjectContext,
FALSE,
DesiredAccess,
Ccb ? Ccb->PreviouslyGrantedAccess : 0,
NULL,
IoGetFileObjectGenericMapping(),
UserMode,
Ccb ? &(Ccb->PreviouslyGrantedAccess) : &LocalAccessMask,
&RC);
SeReleaseSubjectContext(&SubjectContext);
if(!SecurityCheck) {
return RC;
} else
#endif //UDF_ENABLE_SECURITY
if(DesiredAccess & ACCESS_SYSTEM_SECURITY) {
if (!SeSinglePrivilegeCheck(SeExports->SeSecurityPrivilege, UserMode))
return STATUS_ACCESS_DENIED;
Ccb->PreviouslyGrantedAccess |= ACCESS_SYSTEM_SECURITY;
}
#ifdef UDF_ENABLE_SECURITY
}
#endif //UDF_ENABLE_SECURITY
if(FileObject) {
if (Fcb->OpenHandleCount) {
// The FCB is currently in use by some thread.
// We must check whether the requested access/share access
// conflicts with the existing open operations.
RC = IoCheckShareAccess(DesiredAccess, ShareAccess, FileObject,
&(Fcb->NTRequiredFCB->FCBShareAccess), TRUE);
#ifndef UDF_ENABLE_SECURITY
if(Ccb)
Ccb->PreviouslyGrantedAccess |= DesiredAccess;
IoUpdateShareAccess(FileObject, &(Fcb->NTRequiredFCB->FCBShareAccess));
#endif //UDF_ENABLE_SECURITY
} else {
IoSetShareAccess(DesiredAccess, ShareAccess, FileObject, &(Fcb->NTRequiredFCB->FCBShareAccess));
#ifndef UDF_ENABLE_SECURITY
if(Ccb)
Ccb->PreviouslyGrantedAccess = DesiredAccess;
#endif //UDF_ENABLE_SECURITY
RC = STATUS_SUCCESS;
}
} else {
// we get here if given file was opened for internal purposes
RC = STATUS_SUCCESS;
}
return RC;
} // end UDFCheckAccessRights()
NTSTATUS
UDFSetAccessRights(
PFILE_OBJECT FileObject,
PACCESS_STATE AccessState,
PtrUDFFCB Fcb,
PtrUDFCCB Ccb,
ACCESS_MASK DesiredAccess,
USHORT ShareAccess
)
{
#ifndef UDF_ENABLE_SECURITY
ASSERT(Ccb);
ASSERT(Fcb->FileInfo);
return UDFCheckAccessRights(FileObject, AccessState, Fcb, Ccb, DesiredAccess, ShareAccess);
#else //UDF_ENABLE_SECURITY
NTSTATUS RC;
// Set Security on Object
PSECURITY_DESCRIPTOR SecDesc;
SECURITY_SUBJECT_CONTEXT SubjectContext;
BOOLEAN AutoInherit;
ASSERT(Ccb);
ASSERT(Fcb->FileInfo);
SecDesc = UDFLookUpAcl(Fcb->Vcb, FileObject, Fcb);
AutoInherit = UDFIsAStreamDir(Fcb->FileInfo) || UDFIsAStream(Fcb->FileInfo);
if(SecDesc && !AutoInherit) {
// Get caller's User/Primary Group info
SeCaptureSubjectContext(&SubjectContext);
RC = SeAssignSecurity(
Fcb->FileInfo->ParentFile->Dloc->CommonFcb->SecurityDesc,
// NULL,
AccessState->SecurityDescriptor,
&(Fcb->NTRequiredFCB->SecurityDesc),
UDFIsADirectory(Fcb->FileInfo),
&SubjectContext,
IoGetFileObjectGenericMapping(),
NonPagedPool);
SeReleaseSubjectContext(&SubjectContext);
UDFConvertToSelfRelative(&(Fcb->NTRequiredFCB->SecurityDesc));
if(!NT_SUCCESS(RC)) {
Clean_Up_SD:
UDFDeassignAcl(Fcb->NTRequiredFCB, AutoInherit);
return RC;
}
}
RC = UDFCheckAccessRights(FileObject, AccessState, Fcb, Ccb, DesiredAccess, ShareAccess);
if(!NT_SUCCESS(RC))
goto Clean_Up_SD;
return RC;
#endif //UDF_ENABLE_SECURITY
} // end UDFSetAccessRights()