mirror of https://github.com/tongzx/nt5src
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.
1842 lines
48 KiB
1842 lines
48 KiB
//-----------------------------------------------------------------------------
|
|
//
|
|
// Copyright (C) 1992, Microsoft Corporation.
|
|
//
|
|
// File: fsctrl.c
|
|
//
|
|
// Contents:
|
|
// This module implements the File System Control routines for Dsfs called
|
|
// by the dispatch driver.
|
|
//
|
|
// Functions:
|
|
// DfsFsdFileSystemControl
|
|
// DfsFspFileSystemControl
|
|
// DfsCommonFileSystemControl, local
|
|
// DfsUserFsctl, local
|
|
// DfsInsertProvider - Helper routine for DfsFsctrlDefineProvider
|
|
// DfsFsctrlReadCtrs - Read the Dfs driver perfmon counters
|
|
// DfsFsctrlGetServerName - Get name of server given prefix
|
|
// DfsFsctrlReadStruct - return an internal data struct (debug build only)
|
|
// DfsFsctrlReadMem - return internal memory (debug build only)
|
|
// DfsCompleteMountRequest - Completion routine for mount IRP
|
|
// DfsCompleteLoadFsRequest - Completion routine for Load FS IRP
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
#include "dfsprocs.h"
|
|
#include "attach.h"
|
|
#include "registry.h"
|
|
#include "regkeys.h"
|
|
#include "know.h"
|
|
#include "localvol.h"
|
|
#include "lvolinit.h"
|
|
#include "fsctrl.h"
|
|
#include "sitesup.h"
|
|
#include "ipsup.h"
|
|
#include "spcsup.h"
|
|
#include "dfslpc.h"
|
|
#include "dfswml.h"
|
|
|
|
//
|
|
// The local debug trace level
|
|
//
|
|
|
|
#define Dbg (DEBUG_TRACE_FSCTRL)
|
|
|
|
//
|
|
// Local procedure prototypes
|
|
//
|
|
|
|
NTSTATUS
|
|
DfsCommonFileSystemControl (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
DfsUserFsctl (
|
|
IN PIRP Irp
|
|
);
|
|
|
|
|
|
NTSTATUS
|
|
DfsFsctrlStartDfs(
|
|
IN PIRP Irp);
|
|
|
|
VOID DfsSetMachineState();
|
|
|
|
NTSTATUS
|
|
DfsFsctrlGetServerName(
|
|
IN PIRP Irp,
|
|
IN PUCHAR InputBuffer,
|
|
IN ULONG InputBufferLength,
|
|
IN PUCHAR OutputBuffer,
|
|
IN ULONG OutputBufferLength);
|
|
|
|
#if DBG
|
|
NTSTATUS
|
|
DfsFsctrlReadStruct (
|
|
IN PIRP Irp,
|
|
IN PFILE_DFS_READ_STRUCT_PARAM pRsParam,
|
|
IN ULONG InputBufferLength,
|
|
IN OUT PUCHAR OutputBuffer,
|
|
IN ULONG OutputBufferLength
|
|
);
|
|
|
|
NTSTATUS
|
|
DfsFsctrlReadMem (
|
|
IN PIRP Irp,
|
|
IN PFILE_DFS_READ_MEM Request,
|
|
IN ULONG InputBufferLength,
|
|
IN OUT PUCHAR OutputBuffer,
|
|
IN ULONG OutputBufferLength
|
|
);
|
|
#endif
|
|
|
|
NTSTATUS
|
|
DfsCompleteMountRequest(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context
|
|
);
|
|
|
|
NTSTATUS
|
|
DfsCompleteLoadFsRequest(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context
|
|
);
|
|
|
|
NTSTATUS
|
|
DfsFsctrlGetPkt(
|
|
IN PIRP Irp,
|
|
IN PUCHAR OutputBuffer,
|
|
IN ULONG OutputBufferLength);
|
|
|
|
NTSTATUS
|
|
DfsGetPktSize(
|
|
OUT PULONG pSize);
|
|
|
|
NTSTATUS
|
|
DfsGetPktMarshall(
|
|
IN PBYTE Buffer,
|
|
IN ULONG Size);
|
|
|
|
#if DBG
|
|
VOID
|
|
DfsGetDebugFlags(void);
|
|
#endif
|
|
|
|
VOID
|
|
DfsGetEventLogValue(VOID);
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text( PAGE, DfsFsdFileSystemControl )
|
|
#pragma alloc_text( PAGE, DfsCommonFileSystemControl )
|
|
#pragma alloc_text( PAGE, DfsUserFsctl )
|
|
#pragma alloc_text( PAGE, DfsSetMachineState)
|
|
#pragma alloc_text( PAGE, DfsInsertProvider )
|
|
#pragma alloc_text( PAGE, DfsFsctrlGetServerName )
|
|
#pragma alloc_text( PAGE, DfspStringInBuffer)
|
|
#pragma alloc_text( PAGE, DfsFsctrlGetPkt)
|
|
#pragma alloc_text( PAGE, DfsGetPktSize)
|
|
#pragma alloc_text( PAGE, DfsGetPktMarshall)
|
|
|
|
#if DBG
|
|
#pragma alloc_text( PAGE, DfsFsctrlReadStruct )
|
|
#pragma alloc_text( PAGE, DfsFsctrlReadMem )
|
|
#endif // DBG
|
|
|
|
//
|
|
// The following routines cannot be paged because they are completion
|
|
// routines which can be called at raised IRQL
|
|
//
|
|
// DfsCompleteMountRequest
|
|
// DfsCompleteLoadFsRequest
|
|
//
|
|
|
|
#endif // ALLOC_PRAGMA
|
|
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Function: DfsFsdFileSystemControl, public
|
|
//
|
|
// Synopsis: This routine implements the FSD part of FileSystem
|
|
// control operations
|
|
//
|
|
// Arguments: [DeviceObject] -- Supplies the volume device object
|
|
// where the file exists
|
|
// [Irp] -- Supplies the Irp being processed
|
|
//
|
|
// Returns: [NTSTATUS] -- The FSD status for the IRP
|
|
//
|
|
//--------------------------------------------------------------------
|
|
|
|
NTSTATUS
|
|
DfsFsdFileSystemControl (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
) {
|
|
BOOLEAN Wait;
|
|
NTSTATUS Status;
|
|
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
|
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
|
DebugTrace(+1, Dbg, "DfsFsdFileSystemControl\n", 0);
|
|
DFS_TRACE_HIGH(TRACE_IRP, DfsFsdFileSystemControl_Entry,
|
|
LOGPTR(FileObject)
|
|
LOGPTR(Irp));
|
|
|
|
//
|
|
// Call the common FileSystem Control routine, with blocking allowed
|
|
// if synchronous. This opeation needs to special case the mount
|
|
// and verify suboperations because we know they are allowed to block.
|
|
// We identify these suboperations by looking at the file object field
|
|
// and seeing if it's null.
|
|
//
|
|
|
|
if (IoGetCurrentIrpStackLocation(Irp)->FileObject == NULL) {
|
|
|
|
Wait = TRUE;
|
|
|
|
} else {
|
|
|
|
Wait = CanFsdWait( Irp );
|
|
|
|
}
|
|
|
|
FsRtlEnterFileSystem();
|
|
|
|
try {
|
|
|
|
|
|
Status = DfsCommonFileSystemControl( DeviceObject, Irp );
|
|
|
|
} except( DfsExceptionFilter( GetExceptionCode(), 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 = DfsProcessException( Irp, GetExceptionCode() );
|
|
|
|
}
|
|
|
|
FsRtlExitFileSystem();
|
|
|
|
//
|
|
// And return to our caller
|
|
//
|
|
|
|
DebugTrace(-1, Dbg, "DfsFsdFileSystemControl -> %08lx\n", ULongToPtr( Status ));
|
|
DFS_TRACE_HIGH(TRACE_IRP, DfsFsdFileSystemControl_Exit,
|
|
LOGSTATUS(Status)
|
|
LOGPTR(FileObject)
|
|
LOGPTR(Irp));
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Function: DfsCommonFileSystemControl, local
|
|
//
|
|
// Synopsis: This is the common routine for doing FileSystem control
|
|
// operations called by both the FSD and FSP threads
|
|
//
|
|
// Arguments: [DeviceObject] -- The one used to enter our FSD Routine
|
|
// [Irp] -- Supplies the Irp to process
|
|
//
|
|
// Returns: NTSTATUS - The return status for the operation
|
|
//--------------------------------------------------------------------
|
|
|
|
NTSTATUS
|
|
DfsCommonFileSystemControl (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
) {
|
|
NTSTATUS Status;
|
|
PIO_STACK_LOCATION IrpSp, NextIrpSp;
|
|
PFILE_OBJECT FileObject;
|
|
ULONG FsControlCode;
|
|
|
|
|
|
|
|
//
|
|
// Get a pointer to the current Irp stack location
|
|
//
|
|
|
|
IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
|
FileObject = IrpSp->FileObject;
|
|
DFS_TRACE_LOW(TRACE_IRP, DfsCommonFileSystemControl_Entry,
|
|
LOGPTR(FileObject)
|
|
LOGPTR(Irp));
|
|
|
|
FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
|
|
|
|
DebugTrace(+1, Dbg, "DfsCommonFileSystemControl\n", 0);
|
|
DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp);
|
|
DebugTrace( 0, Dbg, "MinorFunction = %08lx\n", IrpSp->MinorFunction);
|
|
|
|
//
|
|
// We know this is a file system control so we'll case on the
|
|
// minor function, and call a internal worker routine to complete
|
|
// the irp.
|
|
//
|
|
switch (IrpSp->MinorFunction) {
|
|
|
|
case IRP_MN_USER_FS_REQUEST:
|
|
|
|
//
|
|
// If the FSCTL is issued via a device that is not
|
|
// the DFS file system device object, then reject the request.
|
|
//
|
|
if (IS_DFS_CTL_CODE( FsControlCode )) {
|
|
if (DeviceObject == DfsData.FileSysDeviceObject) {
|
|
Status = DfsUserFsctl( Irp );
|
|
}
|
|
else {
|
|
DebugTrace(0, Dbg,"Dfs Fsctrl from invalid device object!\n", 0);
|
|
Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
DFS_TRACE_HIGH(ERROR, DfsCommonFileSystemControl_Error_FsctrlFromInvalidDeviceObj,
|
|
LOGPTR(Irp)
|
|
LOGPTR(FileObject)
|
|
LOGSTATUS(Status));
|
|
DfsCompleteRequest( Irp, Status );
|
|
}
|
|
} else if (DeviceObject->DeviceType == FILE_DEVICE_DFS_VOLUME ||
|
|
DeviceObject->DeviceType == FILE_DEVICE_DISK_FILE_SYSTEM) {
|
|
|
|
Status = DfsVolumePassThrough(DeviceObject, Irp);
|
|
|
|
DebugTrace(0, Dbg, "Pass through user fsctrl -> %08lx\n", ULongToPtr( Status ) );
|
|
|
|
} else {
|
|
|
|
DebugTrace(0, Dbg, "Non Dfs Fsctrl code to Dfs File System Object!\n", 0);
|
|
|
|
Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
|
|
DfsCompleteRequest( Irp, Status );
|
|
|
|
}
|
|
break;
|
|
|
|
case IRP_MN_MOUNT_VOLUME:
|
|
case IRP_MN_VERIFY_VOLUME:
|
|
|
|
ASSERT( DeviceObject != NULL );
|
|
|
|
if (DeviceObject->DeviceType == FILE_DEVICE_DFS_VOLUME) {
|
|
|
|
Status = DfsVolumePassThrough(DeviceObject, Irp);
|
|
|
|
DebugTrace(0, Dbg, "Pass through user fsctrl -> %08lx\n", ULongToPtr( Status ) );
|
|
|
|
} else if (DeviceObject->DeviceType == FILE_DEVICE_DISK_FILE_SYSTEM) {
|
|
|
|
//
|
|
// We are processing a MOUNT/VERIFY request being directed to
|
|
// another File System to which we have attached our own
|
|
// Attach File System Object. We setup a completion routine
|
|
// and forward the request.
|
|
//
|
|
|
|
NextIrpSp = IoGetNextIrpStackLocation(Irp);
|
|
(*NextIrpSp) = (*IrpSp);
|
|
|
|
IoSetCompletionRoutine(
|
|
Irp,
|
|
DfsCompleteMountRequest,
|
|
NULL,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE);
|
|
|
|
//
|
|
// We want to pass the real device to the underlying file system
|
|
// so it can do its mount. See the comment in
|
|
// DfsCompleteMountRequest.
|
|
//
|
|
|
|
IrpSp->Parameters.MountVolume.DeviceObject =
|
|
IrpSp->Parameters.MountVolume.Vpb->RealDevice;
|
|
|
|
|
|
//
|
|
// Call the underlying file system via its file system device
|
|
//
|
|
|
|
Status = IoCallDriver(
|
|
((PDFS_ATTACH_FILE_SYSTEM_OBJECT)
|
|
DeviceObject)->TargetDevice,
|
|
Irp );
|
|
|
|
DFS_TRACE_ERROR_HIGH(Status, ALL_ERROR, DfsCommonFileSystemControl_Error_Vol_IoCallDriver,
|
|
LOGSTATUS(Status)
|
|
LOGPTR(FileObject)
|
|
LOGPTR(Irp));
|
|
|
|
} else {
|
|
|
|
//
|
|
// We are processing a MOUNT/VERIFY request being directed to our
|
|
// our File System Device Object. We don't directly support
|
|
// disk volumes, so we simply reject.
|
|
//
|
|
|
|
ASSERT(DeviceObject->DeviceType == FILE_DEVICE_DFS_FILE_SYSTEM);
|
|
|
|
Status = STATUS_NOT_SUPPORTED;
|
|
|
|
DfsCompleteRequest( Irp, Status );
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case IRP_MN_LOAD_FILE_SYSTEM:
|
|
|
|
//
|
|
// This is a "load file system" fsctrl being sent to a file system
|
|
// recognizer to which we are attached. We first detach from the
|
|
// recognizer (so it can delete itself), then setup a completion
|
|
// routine and forward the request.
|
|
//
|
|
|
|
ASSERT( DeviceObject != NULL );
|
|
|
|
IoDetachDevice(
|
|
((PDFS_ATTACH_FILE_SYSTEM_OBJECT) DeviceObject)->TargetDevice);
|
|
|
|
NextIrpSp = IoGetNextIrpStackLocation(Irp);
|
|
(*NextIrpSp) = (*IrpSp);
|
|
|
|
IoSetCompletionRoutine(
|
|
Irp,
|
|
DfsCompleteLoadFsRequest,
|
|
NULL,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE);
|
|
|
|
Status = IoCallDriver(
|
|
((PDFS_ATTACH_FILE_SYSTEM_OBJECT)
|
|
DeviceObject)->TargetDevice,
|
|
Irp );
|
|
|
|
DFS_TRACE_ERROR_HIGH(Status, ALL_ERROR, DfsCommonFileSystemControl_Error_FS_IoCallDriver,
|
|
LOGSTATUS(Status)
|
|
LOGPTR(FileObject)
|
|
LOGPTR(Irp));
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
//
|
|
// Pass through all the rest we dont care about.
|
|
//
|
|
DebugTrace(0, Dbg, "Unknown FS Control Minor Function %08lx\n",
|
|
IrpSp->MinorFunction);
|
|
|
|
Status = DfsVolumePassThrough(DeviceObject, Irp);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
DebugTrace(-1, Dbg, "DfsCommonFileSystemControl -> %08lx\n", ULongToPtr( Status ));
|
|
|
|
DFS_TRACE_LOW(TRACE_IRP, DfsCommonFileSystemControl_Exit,
|
|
LOGSTATUS(Status)
|
|
LOGPTR(FileObject)
|
|
LOGPTR(Irp));
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: DfsCompleteMountRequest, local
|
|
//
|
|
// Synopsis: Completion routine for a MOUNT fsctrl that was passed through
|
|
// to the underlying File System Device Object.
|
|
//
|
|
// This routine will simply see if the MOUNT succeeded. If it
|
|
// did, this routine will call DfsReattachToMountedVolume so
|
|
// any local volumes which were disabled by the unmount will be
|
|
// enabled again.
|
|
//
|
|
// Arguments: [DeviceObject] -- Our Attached File System Object.
|
|
// [Irp] -- The MOUNT fsctrl IRP.
|
|
// [Context] -- Unused
|
|
//
|
|
// Returns: [STATUS_SUCCESS] -- Always.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
NTSTATUS
|
|
DfsCompleteMountRequest(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context)
|
|
{
|
|
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation( Irp );
|
|
PDEVICE_OBJECT targetDevice;
|
|
PVPB vpb;
|
|
|
|
//
|
|
// Determine whether or not the request was successful and act accordingly.
|
|
//
|
|
|
|
DebugTrace(+1, Dbg,
|
|
"DfsCompleteMountRequest: Entered %08lx\n", ULongToPtr( Irp->IoStatus.Status ));
|
|
|
|
if (NT_SUCCESS( Irp->IoStatus.Status )) {
|
|
|
|
//
|
|
// Note that the VPB must be picked up from the target device object
|
|
// in case the file system did a remount of a previous volume, in
|
|
// which case it has replaced the VPB passed in as the target with
|
|
// a previously mounted VPB. Note also that in the mount dispatch
|
|
// routine, this driver *replaced* the DeviceObject pointer with a
|
|
// pointer to the real device, not the device that the file system
|
|
// was supposed to talk to, since this driver does not care.
|
|
//
|
|
|
|
vpb = irpSp->Parameters.MountVolume.DeviceObject->Vpb;
|
|
|
|
targetDevice = IoGetAttachedDevice( vpb->DeviceObject );
|
|
|
|
DebugTrace(0, Dbg, "Target Device %08lx\n", targetDevice);
|
|
|
|
DfsReattachToMountedVolume( targetDevice, vpb );
|
|
|
|
}
|
|
|
|
//
|
|
// If pending was returned, then propogate it to the caller.
|
|
//
|
|
|
|
if (Irp->PendingReturned) {
|
|
IoMarkIrpPending( Irp );
|
|
}
|
|
|
|
DebugTrace(-1, Dbg, "DfsCompleteMountRequest: Exited\n", 0);
|
|
|
|
return( STATUS_SUCCESS );
|
|
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: DfsCompleteLoadFsRequest, local
|
|
//
|
|
// Synopsis: Completion routine for a LOAD_FILE_SYSTEM fsctrl Irp. If
|
|
// the load did not succeed, this routine simply reattaches our
|
|
// Attached File System Object to the recognizer. If the load
|
|
// succeeds, this routine arranges to delete the Attached File
|
|
// System Object that was originally attached to the recognizer.
|
|
//
|
|
// Arguments: [DeviceObject] -- Attached File System Object.
|
|
// [Irp] -- The LOAD_FILE_SYSTEM Fsctrl Irp.
|
|
// [Context] -- Unused.
|
|
//
|
|
// Returns: [STATUS_SUCCESS] -- Always.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
NTSTATUS
|
|
DfsCompleteLoadFsRequest(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context)
|
|
{
|
|
|
|
if (NT_SUCCESS(Irp->IoStatus.Status)) {
|
|
|
|
RemoveEntryList(
|
|
&((PDFS_ATTACH_FILE_SYSTEM_OBJECT) DeviceObject)->FsoLinks);
|
|
|
|
//
|
|
// Due to refcounting done by the IO Subsystem, there's no way to
|
|
// delete the DeviceObject.
|
|
//
|
|
|
|
} else {
|
|
|
|
IoAttachDeviceByPointer(
|
|
DeviceObject,
|
|
((PDFS_ATTACH_FILE_SYSTEM_OBJECT) DeviceObject)->TargetDevice);
|
|
|
|
|
|
}
|
|
|
|
//
|
|
// If pending was returned, then propogate it to the caller
|
|
//
|
|
|
|
if (Irp->PendingReturned) {
|
|
IoMarkIrpPending( Irp );
|
|
}
|
|
|
|
return( STATUS_SUCCESS );
|
|
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Function: DfsUserFsctl, local
|
|
//
|
|
// Synopsis: This is the common routine for implementing the user's
|
|
// requests made through NtFsControlFile.
|
|
//
|
|
// Arguments: [Irp] -- Supplies the Irp being processed
|
|
//
|
|
// Returns: NTSTATUS - The return status for the operation
|
|
//
|
|
//--------------------------------------------------------------------
|
|
|
|
NTSTATUS
|
|
DfsUserFsctl (
|
|
IN PIRP Irp
|
|
) {
|
|
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
|
PIO_STACK_LOCATION NextIrpSp;
|
|
NTSTATUS Status;
|
|
ULONG FsControlCode;
|
|
|
|
ULONG cbOutput;
|
|
ULONG cbInput;
|
|
|
|
PUCHAR InputBuffer;
|
|
PUCHAR OutputBuffer;
|
|
|
|
//
|
|
// Just in case some-one (cough) forgets about it...
|
|
// ...zero information status now!
|
|
//
|
|
|
|
Irp->IoStatus.Information = 0L;
|
|
|
|
FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
|
|
|
|
cbInput = IrpSp->Parameters.FileSystemControl.InputBufferLength;
|
|
|
|
cbOutput = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
|
|
|
|
DebugTrace(+1, Dbg, "DfsUserFsctl: Entered\n", 0);
|
|
DebugTrace( 0, Dbg, "DfsUserFsctl: Cntrl Code -> %08lx\n", ULongToPtr( FsControlCode ));
|
|
DebugTrace( 0, Dbg, "DfsUserFsctl: cbInput -> %08lx\n", ULongToPtr( cbInput ));
|
|
DebugTrace( 0, Dbg, "DfsUserFsctl: cbOutput -> %08lx\n", ULongToPtr( cbOutput ));
|
|
|
|
//
|
|
// All DFS FsControlCodes use METHOD_BUFFERED, so the SystemBuffer
|
|
// is used for both the input and output.
|
|
//
|
|
|
|
InputBuffer = OutputBuffer = Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
DebugTrace( 0, Dbg, "DfsUserFsctl: InputBuffer -> %08lx\n", InputBuffer);
|
|
DebugTrace( 0, Dbg, "DfsUserFsctl: UserBuffer -> %08lx\n", Irp->UserBuffer);
|
|
|
|
//
|
|
// Case on the control code.
|
|
//
|
|
|
|
switch ( FsControlCode ) {
|
|
|
|
case FSCTL_REQUEST_OPLOCK_LEVEL_1:
|
|
case FSCTL_REQUEST_OPLOCK_LEVEL_2:
|
|
case FSCTL_REQUEST_BATCH_OPLOCK:
|
|
case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:
|
|
case FSCTL_OPBATCH_ACK_CLOSE_PENDING:
|
|
case FSCTL_OPLOCK_BREAK_NOTIFY:
|
|
case FSCTL_DFS_READ_METERS:
|
|
case FSCTL_SRV_DFSSRV_IPADDR:
|
|
Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
DfsCompleteRequest( Irp, Status );
|
|
break;
|
|
|
|
case FSCTL_DISMOUNT_VOLUME:
|
|
Status = STATUS_NOT_SUPPORTED;
|
|
DfsCompleteRequest( Irp, Status );
|
|
break;
|
|
|
|
case FSCTL_DFS_GET_VERSION:
|
|
if (OutputBuffer != NULL &&
|
|
cbOutput >= sizeof(DFS_GET_VERSION_ARG)) {
|
|
PDFS_GET_VERSION_ARG parg =
|
|
(PDFS_GET_VERSION_ARG) OutputBuffer;
|
|
parg->Version = 1;
|
|
Status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Information = sizeof(DFS_GET_VERSION_ARG);
|
|
} else {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
DfsCompleteRequest(Irp, Status);
|
|
break;
|
|
|
|
case FSCTL_DFS_IS_ROOT:
|
|
if (DfsData.MachineState == DFS_UNKNOWN) {
|
|
DfsSetMachineState();
|
|
}
|
|
|
|
if (DfsData.MachineState == DFS_ROOT_SERVER) {
|
|
Status = STATUS_SUCCESS;
|
|
} else {
|
|
Status = STATUS_INVALID_DOMAIN_ROLE;
|
|
}
|
|
DfsCompleteRequest(Irp, Status);
|
|
break;
|
|
|
|
case FSCTL_DFS_ISDC:
|
|
|
|
DfsData.IsDC = TRUE;
|
|
Status = STATUS_SUCCESS;
|
|
DfsCompleteRequest(Irp, Status);
|
|
break;
|
|
|
|
case FSCTL_DFS_ISNOTDC:
|
|
|
|
DfsData.IsDC = FALSE;
|
|
Status = STATUS_SUCCESS;
|
|
DfsCompleteRequest(Irp, Status);
|
|
break;
|
|
|
|
case FSCTL_DFS_GET_ENTRY_TYPE:
|
|
Status = DfsFsctrlGetEntryType(
|
|
Irp,
|
|
InputBuffer,
|
|
cbInput,
|
|
OutputBuffer,
|
|
cbOutput);
|
|
break;
|
|
|
|
case FSCTL_DFS_MODIFY_PREFIX:
|
|
Status = DfsFsctrlModifyLocalVolPrefix(
|
|
Irp,
|
|
InputBuffer,
|
|
cbInput
|
|
);
|
|
break;
|
|
|
|
case FSCTL_DFS_CREATE_EXIT_POINT:
|
|
Status = DfsFsctrlCreateExitPoint(
|
|
Irp,
|
|
InputBuffer,
|
|
cbInput,
|
|
OutputBuffer,
|
|
cbOutput
|
|
);
|
|
break;
|
|
|
|
case FSCTL_DFS_DELETE_EXIT_POINT:
|
|
Status = DfsFsctrlDeleteExitPoint(
|
|
Irp,
|
|
InputBuffer,
|
|
cbInput
|
|
);
|
|
break;
|
|
|
|
case FSCTL_DFS_START_DFS:
|
|
|
|
DfsGetEventLogValue();
|
|
#if DBG
|
|
DfsGetDebugFlags();
|
|
#endif // DBG
|
|
|
|
Status = DfsFsctrlStartDfs(
|
|
Irp);
|
|
|
|
if (DfsData.MachineState == DFS_UNKNOWN) {
|
|
DfsSetMachineState();
|
|
}
|
|
|
|
//
|
|
// Try to validate our local partitions with a DC
|
|
//
|
|
|
|
break;
|
|
|
|
case FSCTL_DFS_STOP_DFS:
|
|
|
|
DfsGetEventLogValue();
|
|
#if DBG
|
|
DfsGetDebugFlags();
|
|
#endif // DBG
|
|
|
|
Status = DfsFsctrlStopDfs(
|
|
Irp
|
|
);
|
|
|
|
break;
|
|
|
|
case FSCTL_DFS_RESET_PKT:
|
|
|
|
Status = DfsFsctrlResetPkt(
|
|
Irp
|
|
);
|
|
break;
|
|
|
|
case FSCTL_DFS_MARK_STALE_PKT_ENTRIES:
|
|
|
|
Status = DfsFsctrlMarkStalePktEntries(
|
|
Irp
|
|
);
|
|
break;
|
|
|
|
case FSCTL_DFS_FLUSH_STALE_PKT_ENTRIES:
|
|
|
|
Status = DfsFsctrlFlushStalePktEntries(
|
|
Irp
|
|
);
|
|
break;
|
|
|
|
case FSCTL_DFS_INIT_LOCAL_PARTITIONS:
|
|
DfsInitLocalPartitions();
|
|
Status = STATUS_SUCCESS;
|
|
DfsCompleteRequest( Irp, Status);
|
|
break;
|
|
|
|
case FSCTL_DFS_CREATE_LOCAL_PARTITION:
|
|
Status = DfsFsctrlCreateLocalPartition(
|
|
Irp,
|
|
InputBuffer,
|
|
cbInput
|
|
);
|
|
break;
|
|
|
|
case FSCTL_DFS_CREATE_SITE_INFO:
|
|
Status = DfsFsctrlCreateSiteInfo(
|
|
Irp,
|
|
InputBuffer,
|
|
cbInput
|
|
);
|
|
break;
|
|
|
|
case FSCTL_DFS_DELETE_SITE_INFO:
|
|
Status = DfsFsctrlDeleteSiteInfo(
|
|
Irp,
|
|
InputBuffer,
|
|
cbInput
|
|
);
|
|
break;
|
|
|
|
case FSCTL_DFS_CREATE_IP_INFO:
|
|
Status = DfsFsctrlCreateIpInfo(
|
|
Irp,
|
|
InputBuffer,
|
|
cbInput
|
|
);
|
|
break;
|
|
|
|
case FSCTL_DFS_DELETE_IP_INFO:
|
|
Status = DfsFsctrlDeleteIpInfo(
|
|
Irp,
|
|
InputBuffer,
|
|
cbInput
|
|
);
|
|
break;
|
|
|
|
case FSCTL_DFS_CREATE_SPECIAL_INFO:
|
|
Status = DfsFsctrlCreateSpcInfo(
|
|
DfsData.SpcHashTable,
|
|
Irp,
|
|
InputBuffer,
|
|
cbInput
|
|
);
|
|
break;
|
|
|
|
case FSCTL_DFS_DELETE_SPECIAL_INFO:
|
|
Status = DfsFsctrlDeleteSpcInfo(
|
|
DfsData.SpcHashTable,
|
|
Irp,
|
|
InputBuffer,
|
|
cbInput
|
|
);
|
|
break;
|
|
|
|
case FSCTL_DFS_CREATE_FTDFS_INFO:
|
|
Status = DfsFsctrlCreateSpcInfo(
|
|
DfsData.FtDfsHashTable,
|
|
Irp,
|
|
InputBuffer,
|
|
cbInput
|
|
);
|
|
break;
|
|
|
|
case FSCTL_DFS_DELETE_FTDFS_INFO:
|
|
Status = DfsFsctrlDeleteSpcInfo(
|
|
DfsData.FtDfsHashTable,
|
|
Irp,
|
|
InputBuffer,
|
|
cbInput
|
|
);
|
|
break;
|
|
|
|
case FSCTL_DFS_DELETE_LOCAL_PARTITION:
|
|
Status = DfsFsctrlDeleteLocalPartition(
|
|
Irp,
|
|
InputBuffer,
|
|
cbInput
|
|
);
|
|
break;
|
|
|
|
case FSCTL_DFS_SET_LOCAL_VOLUME_STATE:
|
|
Status = DfsFsctrlSetVolumeState(
|
|
Irp,
|
|
InputBuffer,
|
|
cbInput);
|
|
break;
|
|
|
|
case FSCTL_DFS_SET_SERVICE_STATE:
|
|
Status = DfsFsctrlSetServiceState(
|
|
Irp,
|
|
InputBuffer,
|
|
cbInput);
|
|
break;
|
|
|
|
case FSCTL_DFS_DC_SET_VOLUME_STATE:
|
|
Status = DfsFsctrlDCSetVolumeState(
|
|
Irp,
|
|
InputBuffer,
|
|
cbInput);
|
|
break;
|
|
|
|
case FSCTL_DFS_SET_VOLUME_TIMEOUT:
|
|
Status = DfsFsctrlSetVolumeTimeout(
|
|
Irp,
|
|
InputBuffer,
|
|
cbInput);
|
|
break;
|
|
|
|
case FSCTL_DFS_IS_CHILDNAME_LEGAL:
|
|
Status = PktFsctrlIsChildnameLegal(
|
|
Irp,
|
|
InputBuffer,
|
|
cbInput);
|
|
break;
|
|
|
|
case FSCTL_DFS_PKT_CREATE_ENTRY:
|
|
Status = PktFsctrlCreateEntry(
|
|
Irp,
|
|
InputBuffer,
|
|
cbInput
|
|
);
|
|
break;
|
|
|
|
case FSCTL_DFS_PKT_CREATE_SUBORDINATE_ENTRY:
|
|
Status = PktFsctrlCreateSubordinateEntry(
|
|
Irp,
|
|
InputBuffer,
|
|
cbInput
|
|
);
|
|
break;
|
|
|
|
case FSCTL_DFS_PKT_DESTROY_ENTRY:
|
|
Status = PktFsctrlDestroyEntry(
|
|
Irp,
|
|
InputBuffer,
|
|
cbInput
|
|
);
|
|
break;
|
|
|
|
case FSCTL_DFS_PKT_SET_RELATION_INFO:
|
|
Status = PktFsctrlSetRelationInfo(
|
|
Irp,
|
|
InputBuffer,
|
|
cbInput
|
|
);
|
|
break;
|
|
|
|
case FSCTL_DFS_PKT_GET_RELATION_INFO:
|
|
Status = PktFsctrlGetRelationInfo(
|
|
Irp,
|
|
InputBuffer,
|
|
cbInput,
|
|
OutputBuffer,
|
|
cbOutput
|
|
);
|
|
break;
|
|
|
|
case FSCTL_DFS_GET_SERVER_INFO:
|
|
Status = DfsFsctrlGetServerInfo(
|
|
Irp,
|
|
InputBuffer,
|
|
cbInput,
|
|
OutputBuffer,
|
|
cbOutput);
|
|
break;
|
|
|
|
case FSCTL_DFS_SET_SERVER_INFO:
|
|
Status = PktFsctrlSetServerInfo(
|
|
Irp,
|
|
InputBuffer,
|
|
cbInput);
|
|
break;
|
|
|
|
case FSCTL_DFS_CHECK_STGID_IN_USE:
|
|
Status = DfsFsctrlCheckStgIdInUse(
|
|
Irp,
|
|
InputBuffer,
|
|
cbInput,
|
|
OutputBuffer,
|
|
cbOutput);
|
|
break;
|
|
|
|
case FSCTL_DFS_VERIFY_LOCAL_VOLUME_KNOWLEDGE:
|
|
Status = PktFsctrlVerifyLocalVolumeKnowledge(
|
|
Irp,
|
|
InputBuffer,
|
|
cbInput
|
|
);
|
|
break;
|
|
|
|
case FSCTL_DFS_PRUNE_LOCAL_PARTITION:
|
|
Status = PktFsctrlPruneLocalVolume(
|
|
Irp,
|
|
InputBuffer,
|
|
cbInput);
|
|
break;
|
|
|
|
case FSCTL_DFS_FIX_LOCAL_VOLUME:
|
|
Status = DfsFsctrlFixLocalVolumeKnowledge(Irp,
|
|
InputBuffer,
|
|
cbInput);
|
|
break;
|
|
|
|
|
|
case FSCTL_DFS_GET_SERVER_NAME:
|
|
Status = DfsFsctrlGetServerName(Irp,
|
|
InputBuffer,
|
|
cbInput,
|
|
OutputBuffer,
|
|
cbOutput);
|
|
break;
|
|
|
|
case FSCTL_SRV_DFSSRV_CONNECT:
|
|
Status = PktFsctrlDfsSrvConnect(Irp,
|
|
InputBuffer,
|
|
cbInput);
|
|
break;
|
|
|
|
case FSCTL_DFS_GET_PKT:
|
|
Status = DfsFsctrlGetPkt(Irp,
|
|
OutputBuffer,
|
|
cbOutput);
|
|
|
|
break;
|
|
|
|
|
|
case FSCTL_DFS_GET_NEXT_LONG_DOMAIN_NAME:
|
|
Status = DfsFsctrlGetDomainToRefresh(Irp,
|
|
OutputBuffer,
|
|
cbOutput);
|
|
break;
|
|
|
|
|
|
case FSCTL_DFS_REREAD_REGISTRY:
|
|
DfsGetEventLogValue();
|
|
#if DBG
|
|
DfsGetDebugFlags();
|
|
DbgPrint("DfsDebugTraceLevel=0x%x\n", DfsDebugTraceLevel);
|
|
DbgPrint("DfsEventLog=0x%x\n", DfsEventLog);
|
|
#endif // DBG
|
|
DfspGetMaxReferrals();
|
|
Status = STATUS_SUCCESS;
|
|
DfsCompleteRequest(Irp, Status);
|
|
break;
|
|
|
|
#if DBG
|
|
case FSCTL_DFS_PKT_FLUSH_CACHE:
|
|
Status = PktFsctrlFlushCache(Irp, InputBuffer, cbInput);
|
|
break;
|
|
|
|
case FSCTL_DFS_DBG_BREAK:
|
|
DbgBreakPoint();
|
|
Status = STATUS_SUCCESS;
|
|
DfsCompleteRequest(Irp, Status);
|
|
break;
|
|
|
|
case FSCTL_DFS_DBG_FLAGS:
|
|
DfsDebugTraceLevel = * ((PULONG) InputBuffer);
|
|
Status = STATUS_SUCCESS;
|
|
DfsCompleteRequest(Irp, Status);
|
|
break;
|
|
|
|
case FSCTL_DFS_SHUFFLE_ENTRY:
|
|
Status = PktFsctrlShufflePktEntry(
|
|
Irp,
|
|
InputBuffer,
|
|
cbInput);
|
|
break;
|
|
|
|
|
|
case FSCTL_DFS_INTERNAL_READ_MEM:
|
|
Status = DfsFsctrlReadMem(
|
|
Irp,
|
|
(PFILE_DFS_READ_MEM)InputBuffer,
|
|
cbInput,
|
|
OutputBuffer,
|
|
cbOutput );
|
|
break;
|
|
|
|
case FSCTL_DFS_INTERNAL_READSTRUCT:
|
|
Status = DfsFsctrlReadStruct(
|
|
Irp,
|
|
(PFILE_DFS_READ_STRUCT_PARAM)InputBuffer,
|
|
cbInput,
|
|
OutputBuffer,
|
|
cbOutput );
|
|
break;
|
|
|
|
#endif // DBG
|
|
|
|
default:
|
|
|
|
//
|
|
// This is not a recognized DFS fsctrl.
|
|
//
|
|
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
|
|
DfsCompleteRequest( Irp, STATUS_INVALID_PARAMETER );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
DebugTrace(-1, Dbg, "DfsUserFsctl: Exit -> %08lx\n", ULongToPtr( Status ) );
|
|
return Status;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: DfsFsctrlStartDfs
|
|
//
|
|
// Synopsis: Sets the state of the Dfs driver so that it will start
|
|
// receiving open requests.
|
|
//
|
|
// Arguments: [Irp] --
|
|
//
|
|
// Returns: [STATUS_SUCCESS] -- Successfully set the state to started.
|
|
//
|
|
// [STATUS_UNSUCCESSFUL] -- An error occured trying to set the
|
|
// state of Dfs to started. This is most likely because
|
|
// of a failure to register with the MUP.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
NTSTATUS
|
|
DfsFsctrlStartDfs(
|
|
IN PIRP Irp)
|
|
{
|
|
NTSTATUS status;
|
|
UNICODE_STRING dfsRootDeviceName;
|
|
|
|
STD_FSCTRL_PROLOGUE("DfsFsctrlStartDfs", FALSE, FALSE);
|
|
|
|
RtlInitUnicodeString(&dfsRootDeviceName, DFS_DEVICE_ROOT);
|
|
|
|
DfsSetMachineState();
|
|
|
|
DfsData.OperationalState = DFS_STATE_STARTED;
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
DebugTrace(-1, Dbg, "DfsFsctrlStartDfs - returning %08lx\n", ULongToPtr( status ));
|
|
|
|
DfsCompleteRequest(Irp, status);
|
|
|
|
return( status );
|
|
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: DfsSetMachineState
|
|
//
|
|
// Synopsis: Gets the machine state from the registry and sets it in
|
|
// DfsData structure.
|
|
//
|
|
// Arguments: None
|
|
//
|
|
// Returns: Nothing
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
VOID DfsSetMachineState()
|
|
{
|
|
|
|
NTSTATUS Status;
|
|
|
|
DebugTrace(+1, Dbg, "DfsSetMachineState - Entered\n", 0);
|
|
|
|
Status = KRegSetRoot( wszRegRootVolumes );
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
|
|
DebugTrace(0, Dbg, "Found volumes dir %ws\n", wszRegRootVolumes );
|
|
|
|
DfsData.MachineState = DFS_ROOT_SERVER;
|
|
|
|
KRegCloseRoot();
|
|
|
|
} else if (Status == STATUS_OBJECT_PATH_NOT_FOUND ||
|
|
Status == STATUS_OBJECT_NAME_NOT_FOUND) {
|
|
|
|
//
|
|
// We default to DFS_CLIENT. When we later try to initialize local
|
|
// volumes, if we do have any, we'll upgrade ourselves to
|
|
// DFS_SERVER
|
|
//
|
|
|
|
DfsData.MachineState = DFS_CLIENT;
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
} else {
|
|
|
|
DebugTrace(0, Dbg, "Error %08lx opening volumes dir!\n", ULongToPtr( Status ) );
|
|
|
|
DfsData.MachineState = DFS_UNKNOWN;
|
|
}
|
|
|
|
DebugTrace(-1, Dbg, "DfsSetMachineState - Exited!\n", 0);
|
|
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: DfsInsertProvider
|
|
//
|
|
// Synopsis: Given a provider name, id, and capability, will add a new or
|
|
// overwrite an existing provider definition.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns:
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
NTSTATUS DfsInsertProvider(
|
|
IN PUNICODE_STRING ProviderName,
|
|
IN ULONG fProvCapability,
|
|
IN ULONG eProviderId)
|
|
{
|
|
PPROVIDER_DEF pProv = DfsData.pProvider;
|
|
int iProv;
|
|
|
|
//
|
|
// Find a free provider structure, or overwrite an existing one.
|
|
//
|
|
|
|
for (iProv = 0; iProv < DfsData.cProvider; iProv++, pProv++) {
|
|
if (pProv->eProviderId == eProviderId)
|
|
break;
|
|
}
|
|
|
|
if (iProv >= DfsData.maxProvider) {
|
|
ASSERT(iProv >= DfsData.maxProvider && "Out of provider structs");
|
|
return(STATUS_INSUFFICIENT_RESOURCES);
|
|
|
|
}
|
|
|
|
if (iProv < DfsData.cProvider) {
|
|
|
|
//
|
|
// Decrement reference counts on saved objects
|
|
//
|
|
if (pProv->FileObject)
|
|
ObDereferenceObject(pProv->FileObject);
|
|
if (pProv->DeviceObject)
|
|
ObDereferenceObject(pProv->DeviceObject);
|
|
if (pProv->DeviceName.Buffer)
|
|
ExFreePool(pProv->DeviceName.Buffer);
|
|
}
|
|
|
|
pProv->FileObject = NULL;
|
|
pProv->DeviceObject = NULL;
|
|
|
|
|
|
pProv->eProviderId = (USHORT) eProviderId;
|
|
pProv->fProvCapability = (USHORT) fProvCapability;
|
|
pProv->DeviceName = *ProviderName;
|
|
|
|
if (iProv == DfsData.cProvider) {
|
|
DfsData.cProvider++;
|
|
}
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: DfsFsctrlGetServerName
|
|
//
|
|
// Synopsis: Given a Prefix in Dfs namespace it gets a server name for
|
|
// it.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns:
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
NTSTATUS
|
|
DfsFsctrlGetServerName(
|
|
IN PIRP Irp,
|
|
IN PUCHAR InputBuffer,
|
|
IN ULONG InputBufferLength,
|
|
IN PUCHAR OutputBuffer,
|
|
IN ULONG OutputBufferLength)
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
PDFS_PKT pkt;
|
|
PWCHAR pwchServer = (PWCHAR) OutputBuffer;
|
|
ULONG cChServer = 0;
|
|
ULONG MaxAllowed;
|
|
PDFS_PKT_ENTRY pEntry;
|
|
PWCHAR pwszPrefix = (PWCHAR) InputBuffer;
|
|
UNICODE_STRING ustrPrefix, RemainingPath;
|
|
PDFS_SERVICE pService;
|
|
PWCHAR pwch;
|
|
ULONG i;
|
|
|
|
STD_FSCTRL_PROLOGUE(DfsFsctrlGetServerName, TRUE, TRUE);
|
|
|
|
DebugTrace(+1,Dbg,"DfsFsctrlGetServerName()\n", 0);
|
|
|
|
//
|
|
// InputBuffer is a WCHAR. Check that the buffer is of even size, and
|
|
// has at least one character in it.
|
|
//
|
|
|
|
if (InputBufferLength < sizeof(WCHAR) || (InputBufferLength & 0x1) != 0) {
|
|
|
|
DfsCompleteRequest( Irp, STATUS_INVALID_PARAMETER );
|
|
status = STATUS_INVALID_PARAMETER;
|
|
return status;
|
|
|
|
}
|
|
|
|
//
|
|
// Confirm there's a UNICODE NULL in there somewhere.
|
|
//
|
|
|
|
for (i = 0; i < InputBufferLength / sizeof(WCHAR); i++) {
|
|
|
|
if (pwszPrefix[i] == UNICODE_NULL) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (i >= InputBufferLength / sizeof(WCHAR)) {
|
|
|
|
DfsCompleteRequest( Irp, STATUS_INVALID_PARAMETER );
|
|
status = STATUS_INVALID_PARAMETER;
|
|
return status;
|
|
|
|
}
|
|
|
|
//
|
|
// Need to be able to put at least a UNICODE_NULL in the output buffer
|
|
//
|
|
|
|
if (OutputBufferLength >= sizeof(WCHAR)) {
|
|
|
|
MaxAllowed = OutputBufferLength/sizeof(WCHAR) - 1;
|
|
|
|
} else {
|
|
|
|
DfsCompleteRequest( Irp, STATUS_INVALID_PARAMETER );
|
|
status = STATUS_INVALID_PARAMETER;
|
|
return status;
|
|
|
|
}
|
|
|
|
//
|
|
// Found a UNICODE_NULL in the buffer, so off we go...
|
|
//
|
|
|
|
RtlInitUnicodeString(&ustrPrefix, pwszPrefix);
|
|
|
|
pkt = _GetPkt();
|
|
|
|
PktAcquireExclusive(pkt, TRUE);
|
|
pEntry = PktLookupEntryByPrefix(pkt,
|
|
&ustrPrefix,
|
|
&RemainingPath);
|
|
|
|
if (pEntry == NULL) {
|
|
status = STATUS_OBJECT_NAME_NOT_FOUND;
|
|
} else {
|
|
//
|
|
// If there is a local service then return a NULL string.
|
|
//
|
|
if (pEntry->LocalService != NULL) {
|
|
*pwchServer = UNICODE_NULL;
|
|
cChServer = 1;
|
|
} else {
|
|
if (pEntry->ActiveService != NULL) {
|
|
pService = pEntry->ActiveService;
|
|
} else if (pEntry->Info.ServiceCount == 0) {
|
|
pService = NULL;
|
|
} else {
|
|
|
|
//
|
|
// Take first service.
|
|
//
|
|
|
|
pService = pEntry->Info.ServiceList;
|
|
}
|
|
|
|
if (pService != NULL) {
|
|
|
|
pwch = pService->Address.Buffer;
|
|
ASSERT(*pwch == L'\\');
|
|
pwch++;
|
|
while (*pwch != L'\\') {
|
|
*pwchServer++ = *pwch++;
|
|
if (++cChServer >= MaxAllowed) {
|
|
break;
|
|
}
|
|
}
|
|
*pwchServer = UNICODE_NULL;
|
|
DebugTrace(0, Dbg, "SERVERName Created %ws\n", pwchServer);
|
|
} else {
|
|
DebugTrace(0, Dbg, "No Service Exists for %ws\n", pwszPrefix);
|
|
status = DFS_STATUS_NO_SUCH_ENTRY;
|
|
}
|
|
}
|
|
}
|
|
|
|
PktRelease(pkt);
|
|
|
|
Irp->IoStatus.Information = cChServer * sizeof(WCHAR);
|
|
DfsCompleteRequest( Irp, status );
|
|
|
|
DebugTrace(-1,Dbg,"DfsFsctrlGetServerName: Exit->%08lx\n", ULongToPtr( status ));
|
|
return status;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: DfspValidateString, private
|
|
//
|
|
// Synopsis: Check that a LPWSTR lies within a buffer.
|
|
//
|
|
// Arguments: [pwszString] -- pointer to string
|
|
//
|
|
// Returns: TRUE - string lies within buffer
|
|
// FALSE - bad alignment or string doesn't lie within buffer
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
BOOLEAN
|
|
DfspStringInBuffer(LPWSTR pwszString, PVOID Buffer, ULONG BufferLen)
|
|
{
|
|
PCHAR BufferEnd = (PCHAR)Buffer + BufferLen;
|
|
PWCHAR wcp;
|
|
|
|
//
|
|
// Buffer has to be large enough to at least contain a UNICODE_NULL
|
|
// The buffer has to be aligned correctly
|
|
// The start of the string has to lie within the buffer
|
|
//
|
|
|
|
if (BufferLen < sizeof(WCHAR) ||
|
|
!ALIGNMENT_IS_VALID(Buffer, PWCHAR) ||
|
|
!POINTER_IS_VALID(pwszString, Buffer, BufferLen)
|
|
) {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
//
|
|
// Scan the string and be sure we find a UNICODE_NULL within the buffer
|
|
//
|
|
for (wcp = pwszString; (PCHAR)wcp < BufferEnd; wcp++) {
|
|
|
|
|
|
if (*wcp == UNICODE_NULL) {
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
if ((PCHAR)wcp >= BufferEnd) {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
//
|
|
// Looks good!!
|
|
//
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: DfsFsctrlGetPkt
|
|
//
|
|
// Synopsis: Returns the current (cached Pkt)
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns:
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
NTSTATUS
|
|
DfsFsctrlGetPkt(
|
|
IN PIRP Irp,
|
|
IN PUCHAR OutputBuffer,
|
|
IN ULONG OutputBufferLength)
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
PDFS_PKT pkt;
|
|
BOOLEAN pktLocked = FALSE;
|
|
ULONG cbOutBuffer;
|
|
|
|
|
|
DebugTrace(+1, Dbg, "DfsFsctrlGetPkt\n", 0);
|
|
|
|
STD_FSCTRL_PROLOGUE("DfsFsctrlGetPkt", FALSE, TRUE);
|
|
|
|
pkt = _GetPkt();
|
|
|
|
PktAcquireShared( pkt, TRUE );
|
|
|
|
//
|
|
// Calculate the needed output buffer size
|
|
//
|
|
NtStatus = DfsGetPktSize(&cbOutBuffer);
|
|
|
|
//
|
|
// Let user know if it's too small
|
|
//
|
|
if (OutputBufferLength < cbOutBuffer) {
|
|
|
|
RETURN_BUFFER_SIZE(cbOutBuffer, NtStatus);
|
|
|
|
}
|
|
|
|
if (NT_SUCCESS(NtStatus)) {
|
|
|
|
//
|
|
// Args are ok, and it fits - marshall the data
|
|
//
|
|
NtStatus = DfsGetPktMarshall(OutputBuffer, cbOutBuffer);
|
|
|
|
Irp->IoStatus.Information = cbOutBuffer;
|
|
|
|
}
|
|
|
|
PktRelease(pkt);
|
|
|
|
DfsCompleteRequest( Irp, NtStatus );
|
|
|
|
DebugTrace(-1, Dbg, "DfsFsctrlGetPkt -> %08lx\n", ULongToPtr( NtStatus ) );
|
|
|
|
return( NtStatus );
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: DfsGetPktSize, private
|
|
//
|
|
// Synopsis: Calculates the size needed to return the Pkt. Helper for
|
|
// DfsFsctrlGetPkt().
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
NTSTATUS
|
|
DfsGetPktSize(
|
|
PULONG pSize)
|
|
{
|
|
ULONG EntryCount = 0;
|
|
ULONG i;
|
|
ULONG Size = 0;
|
|
PDFS_PKT_ENTRY pPktEntry;
|
|
PDFS_PKT pkt = _GetPkt();
|
|
|
|
//
|
|
// Walk the linked list of Pkt entries
|
|
//
|
|
|
|
for ( pPktEntry = PktFirstEntry(pkt);
|
|
pPktEntry != NULL;
|
|
pPktEntry = PktNextEntry(pkt, pPktEntry)) {
|
|
|
|
//
|
|
// Space for the Prefix and ShortPrefix, including a UNICODE_NULL
|
|
//
|
|
Size += pPktEntry->Id.Prefix.Length + sizeof(WCHAR);
|
|
Size += pPktEntry->Id.ShortPrefix.Length + sizeof(WCHAR);
|
|
|
|
//
|
|
// Space for an array of pointers to DFS_PKT_ADDRESS_OBJECTS
|
|
//
|
|
Size += sizeof(PDFS_PKT_ADDRESS_OBJECT) * pPktEntry->Info.ServiceCount;
|
|
|
|
//
|
|
// Space for the ServerShare address, plus a UNICODE_NULL, plus the state
|
|
//
|
|
for (i = 0; i < pPktEntry->Info.ServiceCount; i++) {
|
|
|
|
Size += sizeof(USHORT) + pPktEntry->Info.ServiceList[i].Address.Length + sizeof(WCHAR);
|
|
|
|
}
|
|
|
|
EntryCount++;
|
|
|
|
}
|
|
|
|
//
|
|
// Space for the DFS_PKT_ARG, which will have EntryCount objects on the end
|
|
//
|
|
Size += FIELD_OFFSET(DFS_GET_PKT_ARG, EntryObject[EntryCount]);
|
|
|
|
//
|
|
// Make sure the size is a multiple of the size of a PDFS_PKT_ADDRESS_OBJECT, as that is what
|
|
// will be at the end of the buffer
|
|
//
|
|
|
|
while ((Size & (sizeof(PDFS_PKT_ADDRESS_OBJECT)-1)) != 0) {
|
|
Size++;
|
|
}
|
|
|
|
*pSize = Size;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: DfsGetPktMarshall, private
|
|
//
|
|
// Synopsis: Marshalls the Pkt. Helper for DfsFsctrlGetPkt().
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
NTSTATUS
|
|
DfsGetPktMarshall(
|
|
PBYTE Buffer,
|
|
ULONG Size)
|
|
{
|
|
ULONG EntryCount = 0;
|
|
ULONG i;
|
|
ULONG j;
|
|
ULONG Type;
|
|
PCHAR pCh;
|
|
PDFS_PKT_ENTRY pPktEntry;
|
|
PDFS_GET_PKT_ARG pPktArg;
|
|
PDFS_PKT pkt = _GetPkt();
|
|
|
|
//
|
|
// This will be a two-pass operation, the first pass will calculate how
|
|
// much room for the LPWSTR arrays at the end of the buffer, then the
|
|
// second pass will put the strings into place, too.
|
|
//
|
|
|
|
RtlZeroMemory(Buffer,Size);
|
|
|
|
//
|
|
// Point to the end of the buffer
|
|
//
|
|
pCh = (PCHAR)(Buffer + Size);
|
|
|
|
pPktArg = (PDFS_GET_PKT_ARG)Buffer;
|
|
|
|
for ( pPktEntry = PktFirstEntry(pkt);
|
|
pPktEntry != NULL;
|
|
pPktEntry = PktNextEntry(pkt, pPktEntry)) {
|
|
|
|
//
|
|
// Space for an array of pointers to DFS_PKT_ADDRESS_OBJECTS
|
|
//
|
|
pCh -= sizeof(PDFS_PKT_ADDRESS_OBJECT) * pPktEntry->Info.ServiceCount;
|
|
pPktArg->EntryObject[EntryCount].Address = (PDFS_PKT_ADDRESS_OBJECT *)pCh;
|
|
|
|
EntryCount++;
|
|
|
|
}
|
|
|
|
//
|
|
// Now marshall
|
|
//
|
|
|
|
EntryCount = 0;
|
|
for ( pPktEntry = PktFirstEntry(pkt);
|
|
pPktEntry != NULL;
|
|
pPktEntry = PktNextEntry(pkt, pPktEntry)) {
|
|
|
|
pCh -= pPktEntry->Id.Prefix.Length + sizeof(WCHAR);
|
|
pPktArg->EntryObject[EntryCount].Prefix = (LPWSTR)pCh;
|
|
RtlCopyMemory(
|
|
pPktArg->EntryObject[EntryCount].Prefix,
|
|
pPktEntry->Id.Prefix.Buffer,
|
|
pPktEntry->Id.Prefix.Length);
|
|
|
|
pCh -= pPktEntry->Id.ShortPrefix.Length + sizeof(WCHAR);
|
|
pPktArg->EntryObject[EntryCount].ShortPrefix = (LPWSTR)pCh;
|
|
RtlCopyMemory(
|
|
pPktArg->EntryObject[EntryCount].ShortPrefix,
|
|
pPktEntry->Id.ShortPrefix.Buffer,
|
|
pPktEntry->Id.ShortPrefix.Length);
|
|
|
|
pPktArg->EntryObject[EntryCount].Type = pPktEntry->Type;
|
|
pPktArg->EntryObject[EntryCount].USN = pPktEntry->USN;
|
|
pPktArg->EntryObject[EntryCount].ExpireTime = pPktEntry->ExpireTime;
|
|
pPktArg->EntryObject[EntryCount].UseCount = pPktEntry->UseCount;
|
|
pPktArg->EntryObject[EntryCount].Uid = pPktEntry->Id.Uid;
|
|
pPktArg->EntryObject[EntryCount].ServiceCount = pPktEntry->Info.ServiceCount;
|
|
|
|
for (i = 0; i < pPktEntry->Info.ServiceCount; i++) {
|
|
|
|
Type = pPktEntry->Info.ServiceList[i].Type;
|
|
pCh -= sizeof(USHORT) + pPktEntry->Info.ServiceList[i].Address.Length + sizeof(WCHAR);
|
|
pPktArg->EntryObject[EntryCount].Address[i] = (PDFS_PKT_ADDRESS_OBJECT)pCh;
|
|
pPktArg->EntryObject[EntryCount].Address[i]->State = (USHORT)Type;
|
|
|
|
RtlCopyMemory(
|
|
&pPktArg->EntryObject[EntryCount].Address[i]->ServerShare[0],
|
|
pPktEntry->Info.ServiceList[i].Address.Buffer,
|
|
pPktEntry->Info.ServiceList[i].Address.Length);
|
|
|
|
}
|
|
|
|
EntryCount++;
|
|
|
|
}
|
|
|
|
pPktArg->EntryCount = EntryCount;
|
|
|
|
//
|
|
// Convert all the pointers to relative offsets
|
|
//
|
|
|
|
for (i = 0; i < pPktArg->EntryCount; i++) {
|
|
|
|
for (j = 0; j < pPktArg->EntryObject[i].ServiceCount; j++) {
|
|
|
|
POINTER_TO_OFFSET(pPktArg->EntryObject[i].Address[j], Buffer);
|
|
|
|
}
|
|
|
|
POINTER_TO_OFFSET(pPktArg->EntryObject[i].Prefix, Buffer);
|
|
POINTER_TO_OFFSET(pPktArg->EntryObject[i].ShortPrefix, Buffer);
|
|
POINTER_TO_OFFSET(pPktArg->EntryObject[i].Address, Buffer);
|
|
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
#if DBG
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: DfsFsctrlReadMem, local
|
|
//
|
|
// Synopsis: DfsFsctrlReadMem is a debugging function which will return
|
|
// the contents of a chunk of kernel space memory
|
|
//
|
|
// Arguments: [IrpContext] -
|
|
// [Irp] -
|
|
// [Request] -- Pointer to a FILE_DFS_READ_MEM struct,
|
|
// giving the description of the data to be returned.
|
|
// [InputBufferLength] -- Size of InputBuffer
|
|
// [OutputBuffer] -- User's output buffer, in which the
|
|
// data structure will be returned.
|
|
// [OutputBufferLength] -- Size of OutputBuffer
|
|
//
|
|
// Returns: NTSTATUS - STATUS_SUCCESS if no error.
|
|
//
|
|
// Notes: Available in DBG builds only.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
NTSTATUS
|
|
DfsFsctrlReadMem (
|
|
IN PIRP Irp,
|
|
IN PFILE_DFS_READ_MEM Request,
|
|
IN ULONG InputBufferLength,
|
|
IN OUT PUCHAR OutputBuffer,
|
|
IN ULONG OutputBufferLength
|
|
) {
|
|
NTSTATUS Status;
|
|
PUCHAR ReadBuffer;
|
|
ULONG ReadLength;
|
|
|
|
DfsCompleteRequest( Irp, STATUS_INVALID_PARAMETER );
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: DfsFsctrlReadStruct, local
|
|
//
|
|
// Synopsis: DfsFsctrlReadStruct is a debugging function which will return
|
|
// structures associated with the Dfs Server.
|
|
//
|
|
// Arguments: [Irp] -
|
|
// [InputBuffer] -- Pointer to a FILE_DFS_READ_STRUCT_PARAM,
|
|
// giving the description of the data structure to be
|
|
// returned.
|
|
// [InputBufferLength] -- Size of InputBuffer
|
|
// [OutputBuffer] -- User's output buffer, in which the
|
|
// data structure will be returned.
|
|
// [OutputBufferLength] -- Size of OutputBuffer
|
|
//
|
|
// Returns: NTSTATUS - STATUS_SUCCESS if no error.
|
|
//
|
|
// Notes: Available in DBG builds only.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
NTSTATUS
|
|
DfsFsctrlReadStruct (
|
|
IN PIRP Irp,
|
|
IN PFILE_DFS_READ_STRUCT_PARAM pRsParam,
|
|
IN ULONG InputBufferLength,
|
|
IN OUT PUCHAR OutputBuffer,
|
|
IN ULONG OutputBufferLength
|
|
) {
|
|
NTSTATUS Status;
|
|
|
|
NODE_TYPE_CODE NodeTypeCode;
|
|
PUCHAR ReadBuffer;
|
|
ULONG ReadLength;
|
|
|
|
DfsCompleteRequest( Irp, STATUS_INVALID_PARAMETER );
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
#endif
|