You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
523 lines
16 KiB
523 lines
16 KiB
/*++
|
|
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
fsctl.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the mini redirector call down routines pertaining to
|
|
file system control(FSCTL) and Io Device Control (IOCTL) operations on file
|
|
system objects.
|
|
|
|
Author:
|
|
|
|
Yun Lin [YunLin] 27-Oct-2000
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
#include "webdav.h"
|
|
|
|
NTSTATUS
|
|
MrxDAVEfsControlCompletion(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context
|
|
);
|
|
|
|
NTSTATUS
|
|
MrxDAVEfsControl(
|
|
IN OUT PRX_CONTEXT RxContext
|
|
);
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, MRxDAVFsCtl)
|
|
#pragma alloc_text(PAGE, MrxDAVEfsControl)
|
|
#endif
|
|
|
|
//
|
|
// Implementation of functions begins here.
|
|
//
|
|
|
|
NTSTATUS
|
|
MRxDAVFsCtl(
|
|
IN OUT PRX_CONTEXT RxContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine performs an FSCTL operation (remote) on a file across the network
|
|
|
|
Arguments:
|
|
|
|
RxContext - the RDBSS context
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The return status for the operation
|
|
|
|
Notes:
|
|
|
|
The FSCTL's handled by a mini rdr can be classified into one of two categories.
|
|
In the first category are those FSCTL's whose implementation are shared between
|
|
RDBSS and the mini rdr's and in the second category are those FSCTL's which
|
|
are totally implemented by the mini rdr's. To this a third category can be
|
|
added, i.e., those FSCTL's which should never be seen by the mini rdr's. The
|
|
third category is solely intended as a debugging aid.
|
|
|
|
The FSCTL's handled by a mini rdr can be classified based on functionality
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
RxCaptureFobx;
|
|
RxCaptureFcb;
|
|
PLOWIO_CONTEXT pLowIoContext = &RxContext->LowIoContext;
|
|
ULONG FsControlCode = pLowIoContext->ParamsFor.FsCtl.FsControlCode;
|
|
|
|
PAGED_CODE();
|
|
|
|
DavDbgTrace(DAV_TRACE_DETAIL, ("MRxDAVFsCtl: FsControlCode = %08lx\n", FsControlCode));
|
|
|
|
switch (pLowIoContext->ParamsFor.FsCtl.MinorFunction) {
|
|
case IRP_MN_USER_FS_REQUEST:
|
|
case IRP_MN_KERNEL_CALL :
|
|
switch (FsControlCode) {
|
|
case FSCTL_ENCRYPTION_FSCTL_IO :
|
|
case FSCTL_SET_ENCRYPTION :
|
|
case FSCTL_READ_RAW_ENCRYPTED :
|
|
case FSCTL_WRITE_RAW_ENCRYPTED :
|
|
case FSCTL_SET_COMPRESSION :
|
|
case FSCTL_SET_SPARSE :
|
|
case FSCTL_QUERY_ALLOCATED_RANGES :
|
|
Status = MrxDAVEfsControl(RxContext);
|
|
break;
|
|
|
|
default:
|
|
Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
MrxDAVEfsControl(
|
|
IN OUT PRX_CONTEXT RxContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine redirects an EFS FSCTL operation on a remote file to its local cache
|
|
|
|
Arguments:
|
|
|
|
RxContext - the RDBSS context
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The return status for the operation
|
|
|
|
Notes:
|
|
|
|
IMPORTANT!!!
|
|
We acquire the FCB exclusively in this routine. Its very critical that this
|
|
routine has a single exit point. Need to remember this while modifying the
|
|
file.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PLOWIO_CONTEXT pLowIoContext = NULL;
|
|
ULONG FsControlCode = 0, EncryptionOperation = 0;
|
|
PIRP TopIrp = NULL, irp = NULL;
|
|
PIO_STACK_LOCATION irpSp = NULL;
|
|
PWEBDAV_SRV_OPEN davSrvOpen = NULL;
|
|
PWEBDAV_FCB DavFcb = NULL;
|
|
PDEVICE_OBJECT DeviceObject = NULL;
|
|
PENCRYPTION_BUFFER EncryptionBuffer = NULL;
|
|
BOOLEAN ShouldUpdateNameCache = FALSE, ExclusiveFcbAcquired = FALSE;
|
|
BOOLEAN FileWasModified = FALSE;
|
|
KEVENT Event;
|
|
RxCaptureFobx;
|
|
RxCaptureFcb;
|
|
|
|
PAGED_CODE();
|
|
|
|
pLowIoContext = &RxContext->LowIoContext;
|
|
FsControlCode = pLowIoContext->ParamsFor.FsCtl.FsControlCode;
|
|
davSrvOpen = MRxDAVGetSrvOpenExtension(RxContext->pRelevantSrvOpen);
|
|
DavFcb = MRxDAVGetFcbExtension(RxContext->pRelevantSrvOpen->pFcb);
|
|
DeviceObject = davSrvOpen->UnderlyingDeviceObject;
|
|
|
|
//
|
|
// When we come here we do not acquire the FCB. The asserts below confirm
|
|
// this.
|
|
//
|
|
ASSERT(RxIsFcbAcquiredExclusive(RxContext->pRelevantSrvOpen->pFcb) == FALSE);
|
|
ASSERT(RxIsFcbAcquiredShared(RxContext->pRelevantSrvOpen->pFcb) == FALSE);
|
|
|
|
//
|
|
// Since we might be changing the attributes of the FCB, we acquire it
|
|
// exclusive.
|
|
//
|
|
RxAcquireExclusiveFcbResourceInMRx(RxContext->pRelevantSrvOpen->pFcb);
|
|
ExclusiveFcbAcquired = TRUE;
|
|
|
|
DavDbgTrace(DAV_TRACE_DETAIL,
|
|
("MrxDAVEfsControl: IRP = %x, capFcb = %x, capFobx = %x\n",
|
|
RxContext->CurrentIrp, capFcb, capFobx));
|
|
|
|
//
|
|
// We cannot encrypt a SYSTEM file.
|
|
//
|
|
if ((capFcb->Attributes & FILE_ATTRIBUTE_SYSTEM) &&
|
|
!(capFcb->Attributes & FILE_ATTRIBUTE_ENCRYPTED)) {
|
|
DavDbgTrace(DAV_TRACE_ERROR, ("ERROR: MrxDAVEfsControlrol: FILE_ATTRIBUTE_SYSTEM\n"));
|
|
Status = STATUS_ACCESS_DENIED;
|
|
goto EXIT_THE_FUNCTION;
|
|
}
|
|
|
|
if (FsControlCode == FSCTL_SET_ENCRYPTION || FsControlCode == FSCTL_ENCRYPTION_FSCTL_IO) {
|
|
|
|
ULONG InputBufferLength = 0;
|
|
|
|
EncryptionBuffer = (PENCRYPTION_BUFFER)RxContext->CurrentIrpSp->Parameters.FileSystemControl.Type3InputBuffer;
|
|
InputBufferLength = RxContext->CurrentIrpSp->Parameters.FileSystemControl.InputBufferLength;
|
|
|
|
if (EncryptionBuffer == NULL) {
|
|
DavDbgTrace(DAV_TRACE_ERROR, ("ERROR: MrxDAVEfsControlrol: EncryptionBuffer == NULL\n"));
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto EXIT_THE_FUNCTION;
|
|
}
|
|
|
|
//
|
|
// The InputBufferLength should be atleast sizeof(ENCRYPTION_BUFFER).
|
|
//
|
|
if (InputBufferLength < sizeof(ENCRYPTION_BUFFER)) {
|
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|
goto EXIT_THE_FUNCTION;
|
|
}
|
|
|
|
try {
|
|
if (RxContext->CurrentIrp->RequestorMode != KernelMode) {
|
|
ProbeForRead(EncryptionBuffer, InputBufferLength, sizeof(UCHAR));
|
|
}
|
|
EncryptionOperation = EncryptionBuffer->EncryptionOperation;
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
Status = STATUS_INVALID_USER_BUFFER;
|
|
goto EXIT_THE_FUNCTION;
|
|
}
|
|
|
|
}
|
|
|
|
if (NodeType(capFcb) == RDBSS_NTC_STORAGE_TYPE_DIRECTORY) {
|
|
UNICODE_STRING FileName;
|
|
|
|
if (FsControlCode == FSCTL_SET_ENCRYPTION) {
|
|
switch (EncryptionOperation) {
|
|
case FILE_SET_ENCRYPTION:
|
|
case STREAM_SET_ENCRYPTION:
|
|
capFcb->Attributes |= FILE_ATTRIBUTE_ENCRYPTED;
|
|
DavFcb->fFileAttributesChanged = TRUE;
|
|
ShouldUpdateNameCache = TRUE;
|
|
|
|
MRxDAVGetFullDirectoryPath(RxContext,NULL,&FileName);
|
|
|
|
if (FileName.Buffer != NULL) {
|
|
Status = MRxDAVCreateEncryptedDirectoryKey(&FileName);
|
|
}
|
|
|
|
DavDbgTrace(DAV_TRACE_DETAIL,
|
|
("MrxDAVEfsControl: Encrypt Directory. capFcb = %x\n",
|
|
capFcb));
|
|
break;
|
|
|
|
case FILE_CLEAR_ENCRYPTION:
|
|
case STREAM_CLEAR_ENCRYPTION:
|
|
capFcb->Attributes &= ~FILE_ATTRIBUTE_ENCRYPTED;
|
|
DavFcb->fFileAttributesChanged = TRUE;
|
|
ShouldUpdateNameCache = TRUE;
|
|
|
|
MRxDAVGetFullDirectoryPath(RxContext,NULL,&FileName);
|
|
|
|
if (FileName.Buffer != NULL) {
|
|
Status = MRxDAVRemoveEncryptedDirectoryKey(&FileName);
|
|
}
|
|
|
|
DavDbgTrace(DAV_TRACE_DETAIL,
|
|
("MrxDAVEfsControl: Decrypt Directory. capFcb = %x\n",
|
|
capFcb));
|
|
break;
|
|
|
|
default:
|
|
Status = STATUS_NOT_SUPPORTED;
|
|
}
|
|
|
|
goto EXIT_THE_FUNCTION;
|
|
|
|
} else {
|
|
DavDbgTrace(DAV_TRACE_ERROR,
|
|
("ERROR: MrxDAVEfsControl: FSCTL NOT supported. capFcb = %x, "
|
|
"FsControlCode = %x\n", capFcb, FsControlCode));
|
|
Status = STATUS_NOT_SUPPORTED;
|
|
goto EXIT_THE_FUNCTION;
|
|
}
|
|
}
|
|
|
|
if (NodeType(capFcb) != RDBSS_NTC_STORAGE_TYPE_FILE) {
|
|
Status = STATUS_NOT_SUPPORTED;
|
|
goto EXIT_THE_FUNCTION;
|
|
}
|
|
|
|
ASSERT(davSrvOpen->UnderlyingFileObject != NULL);
|
|
ASSERT(davSrvOpen->UnderlyingDeviceObject != NULL);
|
|
|
|
KeInitializeEvent(&(Event), NotificationEvent, FALSE);
|
|
|
|
irp = RxCeAllocateIrpWithMDL(DeviceObject->StackSize, FALSE, NULL);
|
|
if (!irp) {
|
|
DavDbgTrace(DAV_TRACE_ERROR, ("ERROR: MrxDAVEfsControl/RxCeAllocateIrpWithMDL\n"));
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto EXIT_THE_FUNCTION;
|
|
}
|
|
|
|
//
|
|
// Set current thread for IoSetHardErrorOrVerifyDevice.
|
|
//
|
|
irp->Tail.Overlay.Thread = PsGetCurrentThread();
|
|
|
|
//
|
|
// We set the requestor mode to whatever the original IRP had. This is
|
|
// because the underlying filesystem can make the appropriate checks
|
|
// if the original IRP had usermode buffers.
|
|
//
|
|
irp->RequestorMode = RxContext->CurrentIrp->RequestorMode;
|
|
|
|
irp->UserBuffer = RxContext->CurrentIrp->UserBuffer;
|
|
|
|
irp->AssociatedIrp.SystemBuffer = RxContext->CurrentIrp->AssociatedIrp.SystemBuffer;
|
|
|
|
if (RxContext->CurrentIrp->MdlAddress &&
|
|
RxContext->CurrentIrp->MdlAddress->ByteCount != 0) {
|
|
irp->MdlAddress = IoAllocateMdl(irp->UserBuffer,
|
|
RxContext->CurrentIrp->MdlAddress->ByteCount,
|
|
FALSE,
|
|
FALSE,
|
|
NULL);
|
|
if (!irp->MdlAddress) {
|
|
DavDbgTrace(DAV_TRACE_ERROR, ("ERROR: MrxDAVEfsControl/IoAllocateMdl\n"));
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto EXIT_THE_FUNCTION;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Get a pointer to the stack location of the first driver which will be
|
|
// invoked. This is where the function codes and the parameters are set.
|
|
//
|
|
irpSp = IoGetNextIrpStackLocation(irp);
|
|
|
|
irpSp->MajorFunction = (UCHAR)RxContext->MajorFunction;
|
|
|
|
irpSp->MinorFunction = (UCHAR)RxContext->MinorFunction;
|
|
|
|
irpSp->FileObject = davSrvOpen->UnderlyingFileObject;
|
|
|
|
irpSp->Flags = RxContext->CurrentIrpSp->Flags;
|
|
|
|
irpSp->Parameters.FileSystemControl.OutputBufferLength =
|
|
RxContext->CurrentIrpSp->Parameters.FileSystemControl.OutputBufferLength;
|
|
|
|
irpSp->Parameters.FileSystemControl.InputBufferLength =
|
|
RxContext->CurrentIrpSp->Parameters.FileSystemControl.InputBufferLength;
|
|
|
|
irpSp->Parameters.FileSystemControl.FsControlCode =
|
|
RxContext->CurrentIrpSp->Parameters.FileSystemControl.FsControlCode;
|
|
|
|
irpSp->Parameters.FileSystemControl.Type3InputBuffer =
|
|
RxContext->CurrentIrpSp->Parameters.FileSystemControl.Type3InputBuffer;
|
|
|
|
IoSetCompletionRoutine(irp,
|
|
MrxDAVEfsControlCompletion,
|
|
&Event,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE);
|
|
|
|
try {
|
|
|
|
//
|
|
// Save the TopLevel Irp.
|
|
//
|
|
TopIrp = IoGetTopLevelIrp();
|
|
|
|
//
|
|
// Tell the underlying guy he's all clear.
|
|
//
|
|
IoSetTopLevelIrp(NULL);
|
|
|
|
Status = IoCallDriver(DeviceObject,irp);
|
|
|
|
} finally {
|
|
|
|
//
|
|
// Restore my context for unwind.
|
|
//
|
|
IoSetTopLevelIrp(TopIrp);
|
|
|
|
}
|
|
|
|
if ((Status == STATUS_PENDING) || (Status == STATUS_SUCCESS)) {
|
|
|
|
Status = KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
|
|
ASSERT(Status == STATUS_SUCCESS);
|
|
|
|
Status = irp->IoStatus.Status;
|
|
|
|
if ((Status == STATUS_SUCCESS) && (FsControlCode == FSCTL_SET_ENCRYPTION)) {
|
|
|
|
DavDbgTrace(DAV_TRACE_DETAIL, ("MrxDAVEfsControl: FSCTL_SET_ENCRYPTION\n"));
|
|
|
|
switch (EncryptionOperation) {
|
|
|
|
case FILE_SET_ENCRYPTION:
|
|
DavDbgTrace(DAV_TRACE_DETAIL, ("MrxDAVEfsControl: FILE_SET_ENCRYPTION\n"));
|
|
capFcb->Attributes |= FILE_ATTRIBUTE_ENCRYPTED;
|
|
DavFcb->fFileAttributesChanged = TRUE;
|
|
FileWasModified = TRUE;
|
|
DavFcb->DoNotTakeTheCurrentTimeAsLMT = FALSE;
|
|
ShouldUpdateNameCache = TRUE;
|
|
break;
|
|
|
|
case FILE_CLEAR_ENCRYPTION:
|
|
DavDbgTrace(DAV_TRACE_DETAIL, ("MrxDAVEfsControl: FILE_CLEAR_ENCRYPTION\n"));
|
|
capFcb->Attributes &= ~FILE_ATTRIBUTE_ENCRYPTED;
|
|
DavFcb->fFileAttributesChanged = TRUE;
|
|
FileWasModified = TRUE;
|
|
DavFcb->DoNotTakeTheCurrentTimeAsLMT = FALSE;
|
|
ShouldUpdateNameCache = TRUE;
|
|
break;
|
|
|
|
case STREAM_SET_ENCRYPTION:
|
|
DavDbgTrace(DAV_TRACE_DETAIL, ("MrxDAVEfsControl: STREAM_SET_ENCRYPTION\n"));
|
|
capFcb->Attributes |= FILE_ATTRIBUTE_ENCRYPTED;
|
|
DavFcb->fFileAttributesChanged = TRUE;
|
|
FileWasModified = TRUE;
|
|
DavFcb->DoNotTakeTheCurrentTimeAsLMT = FALSE;
|
|
ShouldUpdateNameCache = TRUE;
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( (Status == STATUS_SUCCESS) && (FsControlCode == FSCTL_ENCRYPTION_FSCTL_IO) ) {
|
|
|
|
PWEBDAV_FCB DavFcb = NULL;
|
|
DavFcb = MRxDAVGetFcbExtension(RxContext->pRelevantSrvOpen->pFcb);
|
|
|
|
DavDbgTrace(DAV_TRACE_DETAIL, ("MrxDAVEfsControl: FSCTL_ENCRYPTION_FSCTL_IO\n"));
|
|
|
|
switch (EncryptionOperation) {
|
|
case STREAM_SET_ENCRYPTION:
|
|
DavDbgTrace(DAV_TRACE_DETAIL, ("MrxDAVEfsControl: STREAM_SET_ENCRYPTION\n"));
|
|
capFcb->Attributes |= FILE_ATTRIBUTE_ENCRYPTED;
|
|
DavFcb->fFileAttributesChanged = TRUE;
|
|
FileWasModified = TRUE;
|
|
DavFcb->DoNotTakeTheCurrentTimeAsLMT = FALSE;
|
|
ShouldUpdateNameCache = TRUE;
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
EXIT_THE_FUNCTION:
|
|
|
|
//
|
|
// If we modified the attributes, we need to update the name cache to
|
|
// reflect this change.
|
|
//
|
|
if (Status == STATUS_SUCCESS && ShouldUpdateNameCache) {
|
|
MRxDAVUpdateBasicFileInfoCache(RxContext, capFcb->Attributes, NULL);
|
|
}
|
|
|
|
//
|
|
// If FileWasModified is TRUE and Status is STATUS_SUCCESS, we need to
|
|
// mark this file as having been modified.
|
|
//
|
|
if (Status == STATUS_SUCCESS && FileWasModified) {
|
|
InterlockedExchange(&(DavFcb->FileWasModified), 1);
|
|
}
|
|
|
|
if (ExclusiveFcbAcquired) {
|
|
RxReleaseFcbResourceInMRx(RxContext->pRelevantSrvOpen->pFcb);
|
|
}
|
|
|
|
if (irp) {
|
|
if (irp->MdlAddress) {
|
|
IoFreeMdl(irp->MdlAddress);
|
|
}
|
|
RxCeFreeIrp(irp);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
MrxDAVEfsControlCompletion(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine does not complete the Irp. It is used to signal to a
|
|
synchronous part of the driver that it can proceed.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - unused.
|
|
|
|
Irp - Supplies Irp that the transport has finished processing.
|
|
|
|
Context - Supplies the event associated with the Irp.
|
|
|
|
Return Value:
|
|
|
|
The STATUS_MORE_PROCESSING_REQUIRED so that the IO system stops
|
|
processing Irp stack locations at this point.
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Since this is an IRP Completion routine, this cannot be paged code.
|
|
//
|
|
|
|
if (Context != NULL) {
|
|
KeSetEvent((PKEVENT )Context, 0, FALSE);
|
|
}
|
|
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|