579 lines
13 KiB
C
579 lines
13 KiB
C
/*++
|
||
|
||
Copyright (c) 1989 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
SeInfo.c
|
||
|
||
Abstract:
|
||
|
||
This module implements the Security Info routines for NTFS called by the
|
||
dispatch driver.
|
||
|
||
Author:
|
||
|
||
Gary Kimura [GaryKi] 26-Dec-1991
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "NtfsProc.h"
|
||
|
||
//
|
||
// The debug trace level
|
||
//
|
||
|
||
#define Dbg (DEBUG_TRACE_SEINFO)
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(PAGE, NtfsCommonQuerySecurityInfo)
|
||
#pragma alloc_text(PAGE, NtfsCommonSetSecurityInfo)
|
||
#pragma alloc_text(PAGE, NtfsFsdQuerySecurityInfo)
|
||
#pragma alloc_text(PAGE, NtfsFsdSetSecurityInfo)
|
||
#endif
|
||
|
||
|
||
NTSTATUS
|
||
NtfsFsdQuerySecurityInfo (
|
||
IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine implements the FSD part of the Query Security Information API
|
||
calls.
|
||
|
||
Arguments:
|
||
|
||
VolumeDeviceObject - Supplies the device object to use.
|
||
|
||
Irp - Supplies the Irp being processed
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - The Fsd status for the Irp
|
||
|
||
--*/
|
||
|
||
{
|
||
TOP_LEVEL_CONTEXT TopLevelContext;
|
||
PTOP_LEVEL_CONTEXT ThreadTopLevelContext;
|
||
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
PIRP_CONTEXT IrpContext = NULL;
|
||
|
||
ASSERT_IRP( Irp );
|
||
|
||
UNREFERENCED_PARAMETER( VolumeDeviceObject );
|
||
|
||
PAGED_CODE();
|
||
|
||
DebugTrace( +1, Dbg, ("NtfsFsdQuerySecurityInfo\n") );
|
||
|
||
//
|
||
// Call the common query Information routine
|
||
//
|
||
|
||
FsRtlEnterFileSystem();
|
||
|
||
ThreadTopLevelContext = NtfsSetTopLevelIrp( &TopLevelContext, FALSE, FALSE );
|
||
|
||
do {
|
||
|
||
try {
|
||
|
||
//
|
||
// We are either initiating this request or retrying it.
|
||
//
|
||
|
||
if (IrpContext == NULL) {
|
||
|
||
IrpContext = NtfsCreateIrpContext( Irp, CanFsdWait( Irp ) );
|
||
NtfsUpdateIrpContextWithTopLevel( IrpContext, ThreadTopLevelContext );
|
||
|
||
} else if (Status == STATUS_LOG_FILE_FULL) {
|
||
|
||
NtfsCheckpointForLogFileFull( IrpContext );
|
||
}
|
||
|
||
Status = NtfsCommonQuerySecurityInfo( IrpContext, Irp );
|
||
break;
|
||
|
||
} except(NtfsExceptionFilter( IrpContext, GetExceptionInformation() )) {
|
||
|
||
//
|
||
// We had some trouble trying to perform the requested
|
||
// operation, so we'll abort the I/O request with
|
||
// the error status that we get back from the
|
||
// execption code
|
||
//
|
||
|
||
Status = NtfsProcessException( IrpContext, Irp, GetExceptionCode() );
|
||
}
|
||
|
||
} while (Status == STATUS_CANT_WAIT ||
|
||
Status == STATUS_LOG_FILE_FULL);
|
||
|
||
if (ThreadTopLevelContext == &TopLevelContext) {
|
||
NtfsRestoreTopLevelIrp( ThreadTopLevelContext );
|
||
}
|
||
|
||
FsRtlExitFileSystem();
|
||
|
||
//
|
||
// And return to our caller
|
||
//
|
||
|
||
DebugTrace( -1, Dbg, ("NtfsFsdQuerySecurityInfo -> %08lx\n", Status) );
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
NtfsFsdSetSecurityInfo (
|
||
IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine implements the FSD part of the Set Security Information API
|
||
calls.
|
||
|
||
Arguments:
|
||
|
||
VolumeDeviceObject - Supplies the device object to use.
|
||
|
||
Irp - Supplies the Irp being processed
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - The Fsd status for the Irp
|
||
|
||
--*/
|
||
|
||
{
|
||
TOP_LEVEL_CONTEXT TopLevelContext;
|
||
PTOP_LEVEL_CONTEXT ThreadTopLevelContext;
|
||
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
PIRP_CONTEXT IrpContext = NULL;
|
||
|
||
ASSERT_IRP( Irp );
|
||
|
||
UNREFERENCED_PARAMETER( VolumeDeviceObject );
|
||
|
||
PAGED_CODE();
|
||
|
||
DebugTrace( +1, Dbg, ("NtfsFsdSetSecurityInfo\n") );
|
||
|
||
//
|
||
// Call the common query Information routine
|
||
//
|
||
|
||
FsRtlEnterFileSystem();
|
||
|
||
ThreadTopLevelContext = NtfsSetTopLevelIrp( &TopLevelContext, FALSE, FALSE );
|
||
|
||
do {
|
||
|
||
try {
|
||
|
||
//
|
||
// We are either initiating this request or retrying it.
|
||
//
|
||
|
||
if (IrpContext == NULL) {
|
||
|
||
IrpContext = NtfsCreateIrpContext( Irp, CanFsdWait( Irp ) );
|
||
NtfsUpdateIrpContextWithTopLevel( IrpContext, ThreadTopLevelContext );
|
||
|
||
} else if (Status == STATUS_LOG_FILE_FULL) {
|
||
|
||
NtfsCheckpointForLogFileFull( IrpContext );
|
||
}
|
||
|
||
Status = NtfsCommonSetSecurityInfo( IrpContext, Irp );
|
||
break;
|
||
|
||
} except(NtfsExceptionFilter( IrpContext, GetExceptionInformation() )) {
|
||
|
||
//
|
||
// We had some trouble trying to perform the requested
|
||
// operation, so we'll abort the I/O request with
|
||
// the error status that we get back from the
|
||
// execption code
|
||
//
|
||
|
||
Status = NtfsProcessException( IrpContext, Irp, GetExceptionCode() );
|
||
}
|
||
|
||
} while (Status == STATUS_CANT_WAIT ||
|
||
Status == STATUS_LOG_FILE_FULL);
|
||
|
||
if (ThreadTopLevelContext == &TopLevelContext) {
|
||
NtfsRestoreTopLevelIrp( ThreadTopLevelContext );
|
||
}
|
||
|
||
FsRtlExitFileSystem();
|
||
|
||
//
|
||
// And return to our caller
|
||
//
|
||
|
||
DebugTrace( -1, Dbg, ("NtfsFsdSetSecurityInfo -> %08lx\n", Status) );
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
NtfsCommonQuerySecurityInfo (
|
||
IN PIRP_CONTEXT IrpContext,
|
||
IN PIRP Irp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the common routine for querying security information called by
|
||
both the fsd and fsp threads.
|
||
|
||
Arguments:
|
||
|
||
Irp - Supplies the Irp to process
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - the return status for the operation
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
PIO_STACK_LOCATION IrpSp;
|
||
PFILE_OBJECT FileObject;
|
||
|
||
TYPE_OF_OPEN TypeOfOpen;
|
||
PVCB Vcb;
|
||
PFCB Fcb;
|
||
PSCB Scb;
|
||
PCCB Ccb;
|
||
|
||
BOOLEAN AcquiredFcb = TRUE;
|
||
|
||
ASSERT_IRP_CONTEXT( IrpContext );
|
||
ASSERT_IRP( Irp );
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Get the current Irp stack location
|
||
//
|
||
|
||
IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
||
|
||
DebugTrace( +1, Dbg, ("NtfsCommonQuerySecurityInfo") );
|
||
DebugTrace( 0, Dbg, ("IrpContext = %08lx\n", IrpContext) );
|
||
DebugTrace( 0, Dbg, ("Irp = %08lx\n", Irp) );
|
||
|
||
//
|
||
// Extract and decode the file object
|
||
//
|
||
|
||
FileObject = IrpSp->FileObject;
|
||
TypeOfOpen = NtfsDecodeFileObject( IrpContext, FileObject, &Vcb, &Fcb, &Scb, &Ccb, TRUE );
|
||
|
||
//
|
||
// The only type of opens we accept are user file and directory opens
|
||
//
|
||
|
||
if ((TypeOfOpen != UserFileOpen)
|
||
&& (TypeOfOpen != UserDirectoryOpen)) {
|
||
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
|
||
//
|
||
// If the this handle does not open the entire file then refuse access.
|
||
//
|
||
|
||
} else if (!FlagOn( Ccb->Flags, CCB_FLAG_OPEN_AS_FILE )) {
|
||
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
|
||
} else {
|
||
|
||
//
|
||
// Our operation is to acquire the fcb, do the operation and then
|
||
// release the fcb. If the security descriptor for this file is
|
||
// not already loaded we will release the Fcb and then acquire both
|
||
// the Vcb and Fcb. We must have the Vcb to examine our parent's
|
||
// security descriptor.
|
||
//
|
||
|
||
NtfsAcquireSharedFcb( IrpContext, Fcb, NULL, FALSE );
|
||
|
||
try {
|
||
|
||
if (Fcb->SharedSecurity == NULL) {
|
||
|
||
NtfsReleaseFcb( IrpContext, Fcb );
|
||
AcquiredFcb = FALSE;
|
||
|
||
NtfsAcquireExclusiveFcb( IrpContext, Fcb, NULL, FALSE, FALSE );
|
||
AcquiredFcb = TRUE;
|
||
}
|
||
|
||
Status = NtfsQuerySecurity( IrpContext,
|
||
Fcb,
|
||
&IrpSp->Parameters.QuerySecurity.SecurityInformation,
|
||
(PSECURITY_DESCRIPTOR)Irp->UserBuffer,
|
||
&IrpSp->Parameters.QuerySecurity.Length );
|
||
|
||
if ( Status == STATUS_BUFFER_TOO_SMALL ) {
|
||
|
||
Irp->IoStatus.Information = IrpSp->Parameters.QuerySecurity.Length;
|
||
|
||
Status = STATUS_BUFFER_OVERFLOW;
|
||
}
|
||
|
||
//
|
||
// Abort transaction on error by raising.
|
||
//
|
||
|
||
NtfsCleanupTransaction( IrpContext, Status, FALSE );
|
||
|
||
} finally {
|
||
|
||
DebugUnwind( NtfsCommonQuerySecurityInfo );
|
||
|
||
if (AcquiredFcb) {
|
||
|
||
NtfsReleaseFcb( IrpContext, Fcb );
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// Now complete the request and return to our caller
|
||
//
|
||
|
||
NtfsCompleteRequest( &IrpContext, &Irp, Status );
|
||
|
||
DebugTrace( -1, Dbg, ("NtfsCommonQuerySecurityInfo -> %08lx", Status) );
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
NtfsCommonSetSecurityInfo (
|
||
IN PIRP_CONTEXT IrpContext,
|
||
IN PIRP Irp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the common routine for Setting security information called by
|
||
both the fsd and fsp threads.
|
||
|
||
Arguments:
|
||
|
||
Irp - Supplies the Irp to process
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - the return status for the operation
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
PIO_STACK_LOCATION IrpSp;
|
||
PFILE_OBJECT FileObject;
|
||
|
||
#ifdef _CAIRO_
|
||
PQUOTA_CONTROL_BLOCK OldQuotaControl;
|
||
ULONG OldOwnerId;
|
||
ULONG LargeStdInfo;
|
||
#endif // _CAIRO_
|
||
|
||
TYPE_OF_OPEN TypeOfOpen;
|
||
PVCB Vcb;
|
||
PFCB Fcb;
|
||
PSCB Scb;
|
||
PCCB Ccb;
|
||
|
||
ASSERT_IRP_CONTEXT( IrpContext );
|
||
ASSERT_IRP( Irp );
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Get the current Irp stack location
|
||
//
|
||
|
||
IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
||
|
||
DebugTrace( +1, Dbg, ("NtfsCommonSetSecurityInfo") );
|
||
DebugTrace( 0, Dbg, ("IrpContext = %08lx\n", IrpContext) );
|
||
DebugTrace( 0, Dbg, ("Irp = %08lx\n", Irp) );
|
||
|
||
//
|
||
// Extract and decode the file object
|
||
//
|
||
|
||
FileObject = IrpSp->FileObject;
|
||
TypeOfOpen = NtfsDecodeFileObject( IrpContext, FileObject, &Vcb, &Fcb, &Scb, &Ccb, TRUE );
|
||
|
||
//
|
||
// The only type of opens we accept are user file and directory opens
|
||
//
|
||
|
||
if ((TypeOfOpen != UserFileOpen)
|
||
&& (TypeOfOpen != UserDirectoryOpen)) {
|
||
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
|
||
//
|
||
// If the this handle does not open the entire file then refuse access.
|
||
//
|
||
|
||
} else if (!FlagOn( Ccb->Flags, CCB_FLAG_OPEN_AS_FILE )) {
|
||
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
|
||
} else {
|
||
|
||
//
|
||
// Our operation is to acquire the fcb, do the operation and then
|
||
// release the fcb
|
||
//
|
||
|
||
NtfsAcquireExclusiveFcb( IrpContext, Fcb, NULL, FALSE, FALSE );
|
||
|
||
try {
|
||
|
||
#ifdef _CAIRO_
|
||
|
||
//
|
||
// Capture the current OwnerId, Qutoa Control Block and
|
||
// size of standard information.
|
||
//
|
||
|
||
OldQuotaControl = Fcb->QuotaControl;
|
||
OldOwnerId = Fcb->OwnerId;
|
||
LargeStdInfo = Fcb->FcbState & FCB_STATE_LARGE_STD_INFO;
|
||
|
||
#endif // _CAIRO_
|
||
|
||
Status = NtfsModifySecurity( IrpContext,
|
||
Fcb,
|
||
&IrpSp->Parameters.SetSecurity.SecurityInformation,
|
||
IrpSp->Parameters.SetSecurity.SecurityDescriptor );
|
||
|
||
if (NT_SUCCESS( Status )) {
|
||
|
||
#ifdef _CAIRO_
|
||
//
|
||
// Make sure the new security descriptor Id is written out.
|
||
//
|
||
|
||
NtfsUpdateStandardInformation( IrpContext, Fcb );
|
||
#endif
|
||
}
|
||
|
||
//
|
||
// Abort transaction on error by raising.
|
||
//
|
||
|
||
NtfsCleanupTransaction( IrpContext, Status, FALSE );
|
||
|
||
//
|
||
// Set the flag in the Ccb to indicate this change occurred.
|
||
//
|
||
|
||
SetFlag( Ccb->Flags,
|
||
CCB_FLAG_UPDATE_LAST_CHANGE | CCB_FLAG_SET_ARCHIVE );
|
||
|
||
} finally {
|
||
|
||
DebugUnwind( NtfsCommonSetSecurityInfo );
|
||
|
||
#ifdef _CAIRO_
|
||
if (AbnormalTermination()) {
|
||
|
||
//
|
||
// The request failed. Restore the owner and
|
||
// QuotaControl are restored.
|
||
//
|
||
|
||
if (Fcb->QuotaControl != OldQuotaControl &&
|
||
Fcb->QuotaControl != NULL) {
|
||
|
||
//
|
||
// A new quota control block was assigned.
|
||
// Dereference it.
|
||
//
|
||
|
||
NtfsDereferenceQuotaControlBlock( Fcb->Vcb,
|
||
&Fcb->QuotaControl );
|
||
}
|
||
|
||
Fcb->QuotaControl = OldQuotaControl;
|
||
Fcb->OwnerId = OldOwnerId;
|
||
|
||
if (LargeStdInfo == 0) {
|
||
|
||
//
|
||
// The standard information has be returned to
|
||
// its orginal size.
|
||
//
|
||
|
||
ClearFlag( Fcb->FcbState, FCB_STATE_LARGE_STD_INFO );
|
||
}
|
||
|
||
} else {
|
||
|
||
//
|
||
// The request succeed. If the quota control block was
|
||
// changed then derefence the old block.
|
||
//
|
||
|
||
if (Fcb->QuotaControl != OldQuotaControl &&
|
||
OldQuotaControl != NULL) {
|
||
|
||
NtfsDereferenceQuotaControlBlock( Fcb->Vcb,
|
||
&OldQuotaControl);
|
||
|
||
}
|
||
}
|
||
#endif // _CAIRO_
|
||
|
||
NtfsReleaseFcb( IrpContext, Fcb );
|
||
}
|
||
}
|
||
|
||
//
|
||
// Now complete the request and return to our caller
|
||
//
|
||
|
||
NtfsCompleteRequest( &IrpContext, &Irp, Status );
|
||
|
||
DebugTrace( -1, Dbg, ("NtfsCommonSetSecurityInfo -> %08lx", Status) );
|
||
|
||
return Status;
|
||
}
|
||
|