Leaked source code of windows server 2003
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

/*++
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;
}