//////////////////////////////////////////////////////////////////// // 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()