mirror of https://github.com/lianthony/NT4.0
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.
4099 lines
110 KiB
4099 lines
110 KiB
/*++
|
|
|
|
Copyright (c) 1990 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
fsctl.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the NT redirector NtFsControlFile API's
|
|
|
|
Author:
|
|
|
|
Larry Osterman (LarryO) 19-Jun-1990
|
|
|
|
Revision History:
|
|
|
|
19-Jun-1990 LarryO
|
|
|
|
Created
|
|
|
|
--*/
|
|
|
|
#define INCLUDE_SMB_TRANSACTION
|
|
|
|
#ifdef _CAIRO_
|
|
#define INCLUDE_SMB_CAIRO
|
|
#endif // _CAIRO_
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
DBGSTATIC
|
|
NTSTATUS
|
|
StartRedirector (
|
|
IN BOOLEAN Wait,
|
|
IN BOOLEAN InFsd,
|
|
IN PICB Icb,
|
|
IN PFS_DEVICE_OBJECT DeviceObject,
|
|
IN PLMR_REQUEST_PACKET Packet,
|
|
IN ULONG PacketLength,
|
|
IN PWKSTA_INFO_502 WkstaBuffer,
|
|
IN ULONG WkstaBufferLength
|
|
);
|
|
|
|
DBGSTATIC
|
|
NTSTATUS
|
|
StopRedirector (
|
|
IN BOOLEAN Wait,
|
|
IN BOOLEAN InFsd,
|
|
IN PFS_DEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
);
|
|
|
|
DBGSTATIC
|
|
NTSTATUS
|
|
SetConfigInfo (
|
|
IN BOOLEAN Wait,
|
|
IN BOOLEAN InFsd,
|
|
IN PICB Icb,
|
|
IN PFS_DEVICE_OBJECT DeviceObject,
|
|
IN PLMR_REQUEST_PACKET InputBuffer,
|
|
IN OUT PULONG InputBufferLength,
|
|
IN PWKSTA_INFO_502 WkstaBuffer,
|
|
IN ULONG OutputBufferLength
|
|
);
|
|
|
|
DBGSTATIC
|
|
NTSTATUS
|
|
GetConfigInfo (
|
|
IN BOOLEAN Wait,
|
|
IN BOOLEAN InFsd,
|
|
IN PICB Icb,
|
|
IN PLMR_REQUEST_PACKET InputBuffer,
|
|
IN OUT PULONG InputBufferLength,
|
|
IN PWKSTA_INFO_502 WkstaBuffer,
|
|
IN ULONG OutputBufferLength
|
|
);
|
|
|
|
DBGSTATIC
|
|
NTSTATUS
|
|
GetConnectInfo (
|
|
IN BOOLEAN Wait,
|
|
IN BOOLEAN InFsd,
|
|
IN PICB Icb,
|
|
IN PLMR_REQUEST_PACKET InputBuffer,
|
|
IN OUT PULONG InputBufferLength,
|
|
IN PUCHAR OutputBuffer,
|
|
IN ULONG OutputBufferLength,
|
|
IN ULONG OutputBufferDisplacement
|
|
);
|
|
|
|
DBGSTATIC
|
|
NTSTATUS
|
|
EnumerateConnections (
|
|
IN BOOLEAN Wait,
|
|
IN BOOLEAN InFsd,
|
|
IN PIRP Irp,
|
|
IN PICB Icb,
|
|
IN PLMR_REQUEST_PACKET InputBuffer,
|
|
IN OUT PULONG InputBufferLength,
|
|
IN PUCHAR OutputBuffer,
|
|
IN ULONG OutputBufferLength,
|
|
IN ULONG OutputBufferDisplacement
|
|
);
|
|
|
|
DBGSTATIC
|
|
NTSTATUS
|
|
DeleteConnection (
|
|
IN BOOLEAN Wait,
|
|
IN BOOLEAN InFsd,
|
|
IN PIRP Irp OPTIONAL,
|
|
IN PICB Icb,
|
|
IN PLMR_REQUEST_PACKET InputBuffer,
|
|
IN ULONG InputBufferLength
|
|
);
|
|
|
|
DBGSTATIC
|
|
NTSTATUS
|
|
BindToTransport (
|
|
IN BOOLEAN Wait,
|
|
IN BOOLEAN InFsd,
|
|
IN PICB Icb,
|
|
IN PLMR_REQUEST_PACKET InputBuffer,
|
|
IN ULONG InputBufferLength
|
|
);
|
|
|
|
|
|
DBGSTATIC
|
|
NTSTATUS
|
|
UnBindFromTransport (
|
|
IN BOOLEAN Wait,
|
|
IN BOOLEAN InFsd,
|
|
IN PIRP Irp,
|
|
IN PICB Icb,
|
|
IN PLMR_REQUEST_PACKET InputBuffer,
|
|
IN ULONG InputBufferLength
|
|
);
|
|
|
|
DBGSTATIC
|
|
NTSTATUS
|
|
EnumTransports (
|
|
IN BOOLEAN Wait,
|
|
IN BOOLEAN InFsd,
|
|
IN PICB Icb,
|
|
IN PLMR_REQUEST_PACKET InputBuffer,
|
|
IN OUT PULONG InputBufferLength,
|
|
IN PUCHAR OutputBuffer,
|
|
IN ULONG OutputBufferLength,
|
|
IN ULONG OutputBufferDisplacement
|
|
);
|
|
|
|
DBGSTATIC
|
|
NTSTATUS
|
|
AddIdentity (
|
|
IN BOOLEAN Wait,
|
|
IN PFS_DEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
);
|
|
|
|
DBGSTATIC
|
|
NTSTATUS
|
|
DeleteIdentity (
|
|
IN BOOLEAN Wait,
|
|
IN PFS_DEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
);
|
|
|
|
DBGSTATIC
|
|
NTSTATUS
|
|
GetHintSize (
|
|
IN BOOLEAN Wait,
|
|
IN PFS_DEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
);
|
|
|
|
DBGSTATIC
|
|
NTSTATUS
|
|
UserTransaction (
|
|
IN BOOLEAN Wait,
|
|
IN BOOLEAN InFsd,
|
|
IN PIRP Irp,
|
|
IN PICB Icb,
|
|
IN PLMR_TRANSACTION InputBuffer,
|
|
IN OUT PULONG InputBufferLength
|
|
);
|
|
|
|
DBGSTATIC
|
|
NTSTATUS
|
|
EnumPrintQueue (
|
|
IN BOOLEAN Wait,
|
|
IN BOOLEAN InFsd,
|
|
IN PIRP Irp,
|
|
IN PICB Icb,
|
|
IN PLMR_REQUEST_PACKET InputBuffer,
|
|
IN OUT PULONG InputBufferLength,
|
|
IN ULONG OutputBufferLength
|
|
);
|
|
|
|
DBGSTATIC
|
|
NTSTATUS
|
|
GetPrintJobId (
|
|
IN BOOLEAN Wait,
|
|
IN BOOLEAN InFsd,
|
|
IN PIRP Irp,
|
|
IN PICB Icb,
|
|
IN PLMR_REQUEST_PACKET InputBuffer,
|
|
IN OUT PULONG InputBufferLength,
|
|
IN PVOID OutputBuffer,
|
|
IN ULONG OutputBufferLength
|
|
);
|
|
|
|
DBGSTATIC
|
|
BOOLEAN
|
|
PackConnectEntry (
|
|
IN ULONG Level,
|
|
IN OUT PCHAR *BufferStart,
|
|
IN OUT PCHAR *BufferEnd,
|
|
IN ULONG BufferDisplacement,
|
|
IN PUNICODE_STRING DeviceName,
|
|
IN PCONNECTLISTENTRY Cle,
|
|
IN PSECURITY_ENTRY Se,
|
|
OUT PULONG TotalBytesNeeded
|
|
);
|
|
|
|
NTSTATUS
|
|
RdrConvertType3FsControlToType2FsControl (
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
);
|
|
|
|
DBGSTATIC
|
|
NTSTATUS
|
|
GetStatistics (
|
|
IN BOOLEAN Wait,
|
|
IN BOOLEAN InFsd,
|
|
IN PIRP Irp,
|
|
IN PICB Icb,
|
|
IN PLMR_REQUEST_PACKET InputBuffer,
|
|
IN OUT PULONG InputBufferLength,
|
|
IN ULONG OutputBufferLength
|
|
);
|
|
|
|
DBGSTATIC
|
|
NTSTATUS
|
|
StartSmbTrace (
|
|
IN BOOLEAN Wait,
|
|
IN BOOLEAN InFsd,
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp,
|
|
IN PLMR_REQUEST_PACKET InputBuffer,
|
|
IN ULONG InputBufferLength,
|
|
IN ULONG OutputBufferLength
|
|
);
|
|
|
|
DBGSTATIC
|
|
NTSTATUS
|
|
StopSmbTrace (
|
|
IN BOOLEAN Wait,
|
|
IN BOOLEAN InFsd,
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
);
|
|
|
|
NTSTATUS
|
|
GetDfsReferral(
|
|
IN PIRP Irp,
|
|
IN PICB Icb,
|
|
IN PCHAR InputBuffer,
|
|
IN ULONG InputBufferLength,
|
|
IN PUCHAR OutputBuffer,
|
|
IN ULONG OutputBufferLength
|
|
);
|
|
|
|
NTSTATUS
|
|
ReportDfsInconsistency(
|
|
IN PIRP Irp,
|
|
IN PICB Icb,
|
|
IN PCHAR InputBuffer,
|
|
IN ULONG InputBufferLength
|
|
);
|
|
|
|
DBGSTATIC
|
|
NTSTATUS
|
|
RdrIssueNtIoctl(
|
|
IN BOOLEAN Wait,
|
|
IN BOOLEAN InFsd,
|
|
IN PIRP Irp,
|
|
IN PICB Icb,
|
|
IN ULONG Function,
|
|
IN PCHAR InputBuffer,
|
|
IN ULONG InputBufferLength,
|
|
IN PUCHAR OutputBuffer,
|
|
IN OUT PULONG OutputBufferLength
|
|
);
|
|
|
|
#ifdef RASAUTODIAL
|
|
VOID
|
|
RdrAcdBind(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
RdrAcdUnbind(
|
|
VOID
|
|
);
|
|
#endif // RASAUTODIAL
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, RdrFsdFsControlFile)
|
|
#pragma alloc_text(PAGE, RdrFspFsControlFile)
|
|
#pragma alloc_text(PAGE, RdrFscFsControlFile)
|
|
#pragma alloc_text(PAGE, StartRedirector)
|
|
#pragma alloc_text(PAGE, BindToTransport)
|
|
#pragma alloc_text(PAGE, UnBindFromTransport)
|
|
#pragma alloc_text(PAGE, EnumTransports)
|
|
#pragma alloc_text(PAGE, SetConfigInfo)
|
|
#pragma alloc_text(PAGE, GetConfigInfo)
|
|
#pragma alloc_text(PAGE, GetConnectInfo)
|
|
#pragma alloc_text(PAGE, EnumerateConnections)
|
|
#pragma alloc_text(PAGE, UserTransaction)
|
|
#pragma alloc_text(PAGE, EnumPrintQueue)
|
|
#pragma alloc_text(PAGE, GetPrintJobId)
|
|
#pragma alloc_text(PAGE, DeleteConnection)
|
|
#pragma alloc_text(PAGE, RdrConvertType3FsControlToType2FsControl)
|
|
#pragma alloc_text(PAGE, PackConnectEntry)
|
|
#pragma alloc_text(PAGE, StopRedirector)
|
|
#pragma alloc_text(PAGE, GetHintSize)
|
|
#pragma alloc_text(PAGE, RdrFsdDeviceIoControlFile)
|
|
#pragma alloc_text(PAGE, RdrFspDeviceIoControlFile)
|
|
#pragma alloc_text(PAGE, RdrFscDeviceIoControlFile)
|
|
#pragma alloc_text(PAGE, StartSmbTrace)
|
|
#pragma alloc_text(PAGE, StopSmbTrace)
|
|
|
|
#pragma alloc_text(PAGE2VC, GetStatistics)
|
|
|
|
#endif
|
|
|
|
NTSTATUS
|
|
RdrFsdFsControlFile (
|
|
IN PFS_DEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called when the last handle to the NT Rdr device
|
|
driver is closed.
|
|
|
|
Arguments:
|
|
|
|
IN PDEVICE_OBJECT DeviceObject - Supplies a device object for the request.
|
|
IN PIRP Irp - Supplies an IRP for the create request.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Final Status of operation
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
PAGED_CODE();
|
|
|
|
FsRtlEnterFileSystem();
|
|
|
|
Status = RdrFscFsControlFile(TRUE, IoIsOperationSynchronous(Irp),
|
|
DeviceObject,
|
|
Irp);
|
|
FsRtlExitFileSystem();
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
RdrFspFsControlFile (
|
|
IN PFS_DEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called when the last handle to the NT Rdr device
|
|
driver is closed.
|
|
|
|
Arguments:
|
|
|
|
IN PDEVICE_OBJECT DeviceObject - Supplies a device object for the request.
|
|
IN PIRP Irp - Supplies an IRP for the create request.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Final Status of operation
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
PAGED_CODE();
|
|
|
|
Status = RdrFscFsControlFile(FALSE, TRUE,
|
|
DeviceObject,
|
|
Irp);
|
|
return Status;
|
|
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
RdrFscFsControlFile (
|
|
IN BOOLEAN InFsd,
|
|
IN BOOLEAN Wait,
|
|
IN PFS_DEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called when the last handle to the NT Rdr device
|
|
driver is closed.
|
|
|
|
Arguments:
|
|
|
|
IN BOOLEAN InFsd - True if the request is from the FSD, false if from FSP.
|
|
IN BOOLEAN Wait - True if the Rdr can tie up the users thread for this
|
|
request.
|
|
IN PDEVICE_OBJECT DeviceObject - Supplies a device object for the request.
|
|
IN PIRP Irp - Supplies an IRP for the create request.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Final Status of operation
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
PVOID InputBuffer;
|
|
ULONG InputBufferLength;
|
|
PVOID OutputBuffer;
|
|
ULONG OutputBufferLength;
|
|
ULONG FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
|
|
|
|
//
|
|
// For cairo, if when we post a method 3 fsctl, we don't convert it to
|
|
// type 2. Instead, in the FSP, we attach to the originating process
|
|
// to gain access to the user buffers. fAttached indicates whether we
|
|
// have done this attach. fHandledMethod3 indicates whether we
|
|
// handled the method 3 fsctl as is or converted it.
|
|
//
|
|
|
|
BOOLEAN fAttached = FALSE;
|
|
BOOLEAN fHandledMethod3 = FALSE;
|
|
|
|
|
|
PAGED_CODE();
|
|
try {
|
|
//
|
|
// Before we call the worker functions, prep the parameters to those
|
|
// functions.
|
|
//
|
|
|
|
//
|
|
// The lengths of the various buffers are easy to find, they're in the
|
|
// Irp stack location.
|
|
//
|
|
|
|
OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
|
|
|
|
InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
|
|
|
|
//
|
|
// The input buffer is either in Irp->AssociatedIrp.SystemBuffer, or
|
|
// in the Type3InputBuffer for type 3 IRP's.
|
|
//
|
|
|
|
InputBuffer = Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
//
|
|
// If we are in the FSD, then the input buffer is in Type3InputBuffer
|
|
// on type 3 api's, not in SystemBuffer.
|
|
//
|
|
|
|
if (InputBuffer == NULL) {
|
|
|
|
//
|
|
// This had better be a type 3 IOCTL, or the input buffer had
|
|
// better be 0 length.
|
|
//
|
|
|
|
ASSERT (((FsControlCode & 3) == METHOD_NEITHER) || (IrpSp->Parameters.FileSystemControl.InputBufferLength == 0));
|
|
|
|
if ((IrpSp->Parameters.FileSystemControl.InputBufferLength != 0) &&
|
|
((FsControlCode & 3) == METHOD_NEITHER)) {
|
|
|
|
//
|
|
// And we had better be in the FSD.
|
|
//
|
|
|
|
ASSERT (InFsd);
|
|
|
|
InputBuffer = IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
|
|
}
|
|
}
|
|
|
|
//
|
|
// The output buffer is either probed/locked in memory, or is
|
|
// available in the input buffer.
|
|
//
|
|
|
|
try {
|
|
RdrMapUsersBuffer(Irp, &OutputBuffer, IrpSp->Parameters.FileSystemControl.OutputBufferLength);
|
|
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
return Status = GetExceptionCode();
|
|
}
|
|
|
|
if (IrpSp->MinorFunction == IRP_MN_USER_FS_REQUEST) {
|
|
switch (FsControlCode) {
|
|
|
|
//
|
|
// Named Pipe API's supported by the redirector
|
|
//
|
|
|
|
case FSCTL_PIPE_PEEK:
|
|
|
|
Status = RdrNpPeek( Wait, InFsd, Irp, ICB_OF(IrpSp), InputBuffer, &OutputBufferLength );
|
|
|
|
//
|
|
// Update the output buffer length to indicate the true output
|
|
// buffer length.
|
|
//
|
|
|
|
Irp->IoStatus.Information = OutputBufferLength;
|
|
break;
|
|
|
|
case FSCTL_PIPE_TRANSCEIVE:
|
|
|
|
Status = RdrNpTransceive( Wait, InFsd, Irp, ICB_OF(IrpSp), InputBuffer, InputBufferLength, OutputBuffer, &OutputBufferLength);
|
|
|
|
//
|
|
// Update the output buffer length to indicate the true output
|
|
// buffer length.
|
|
//
|
|
|
|
Irp->IoStatus.Information = OutputBufferLength;
|
|
break;
|
|
|
|
case FSCTL_PIPE_WAIT:
|
|
Status = RdrNpWait( Wait, InFsd, Irp, ICB_OF(IrpSp), InputBuffer, InputBufferLength);
|
|
break;
|
|
|
|
//
|
|
// Redirector specific API's supported by the redirector
|
|
//
|
|
|
|
case FSCTL_LMR_START:
|
|
Status = StartRedirector(Wait, InFsd, ICB_OF(IrpSp), DeviceObject, InputBuffer, InputBufferLength, OutputBuffer, OutputBufferLength);
|
|
break;
|
|
|
|
case FSCTL_LMR_STOP:
|
|
Status = StopRedirector(Wait, InFsd, DeviceObject, Irp, IrpSp);
|
|
break;
|
|
|
|
case FSCTL_LMR_SET_CONFIG_INFO:
|
|
Status = SetConfigInfo(Wait, InFsd, ICB_OF(IrpSp), DeviceObject, InputBuffer, &InputBufferLength, OutputBuffer, OutputBufferLength);
|
|
Irp->IoStatus.Information = InputBufferLength;
|
|
break;
|
|
|
|
case FSCTL_LMR_GET_CONFIG_INFO:
|
|
Status = GetConfigInfo(Wait, InFsd, ICB_OF(IrpSp), InputBuffer, &InputBufferLength, OutputBuffer, OutputBufferLength);
|
|
Irp->IoStatus.Information = InputBufferLength;
|
|
break;
|
|
|
|
case FSCTL_LMR_GET_CONNECTION_INFO:
|
|
Status = GetConnectInfo(Wait, InFsd, ICB_OF(IrpSp), InputBuffer, &InputBufferLength, OutputBuffer, OutputBufferLength, (PUCHAR)OutputBuffer - (PUCHAR)Irp->UserBuffer);
|
|
Irp->IoStatus.Information = InputBufferLength;
|
|
break;
|
|
|
|
case FSCTL_LMR_ENUMERATE_CONNECTIONS:
|
|
Status = EnumerateConnections(Wait, InFsd, Irp, ICB_OF(IrpSp), InputBuffer, &InputBufferLength, OutputBuffer, OutputBufferLength, (PUCHAR)OutputBuffer - (PUCHAR)Irp->UserBuffer);
|
|
Irp->IoStatus.Information = InputBufferLength;
|
|
break;
|
|
|
|
case FSCTL_LMR_GET_VERSIONS:
|
|
Status = STATUS_NOT_SUPPORTED;
|
|
break;
|
|
|
|
case FSCTL_LMR_DELETE_CONNECTION:
|
|
Status = DeleteConnection(Wait, InFsd, Irp, ICB_OF(IrpSp), InputBuffer, InputBufferLength);
|
|
break;
|
|
|
|
case FSCTL_LMR_BIND_TO_TRANSPORT:
|
|
#ifdef RDR_PNP_POWER
|
|
Status = RdrRegisterForPnpNotifications();
|
|
#else
|
|
Status = BindToTransport(Wait, InFsd, ICB_OF(IrpSp), InputBuffer, InputBufferLength);
|
|
#endif
|
|
break;
|
|
|
|
case FSCTL_LMR_UNBIND_FROM_TRANSPORT:
|
|
Status = UnBindFromTransport(Wait, InFsd, Irp, ICB_OF(IrpSp), InputBuffer, InputBufferLength);
|
|
break;
|
|
|
|
case FSCTL_LMR_ENUMERATE_TRANSPORTS:
|
|
Status = EnumTransports(Wait, InFsd, ICB_OF(IrpSp), InputBuffer, &InputBufferLength, OutputBuffer, OutputBufferLength, (PUCHAR)OutputBuffer - (PUCHAR)Irp->UserBuffer);
|
|
Irp->IoStatus.Information = InputBufferLength;
|
|
break;
|
|
|
|
case FSCTL_LMR_GET_HINT_SIZE:
|
|
Status = GetHintSize(Wait, DeviceObject, Irp, IrpSp);
|
|
break;
|
|
|
|
case FSCTL_LMR_TRANSACT:
|
|
Status = UserTransaction(Wait, InFsd, Irp, ICB_OF(IrpSp), InputBuffer, &InputBufferLength);
|
|
Irp->IoStatus.Information = InputBufferLength;
|
|
break;
|
|
|
|
case FSCTL_LMR_ENUMERATE_PRINT_INFO:
|
|
Status = EnumPrintQueue(Wait, InFsd, Irp, ICB_OF(IrpSp), InputBuffer, &InputBufferLength, OutputBufferLength);
|
|
Irp->IoStatus.Information = InputBufferLength;
|
|
break;
|
|
|
|
case FSCTL_GET_PRINT_ID:
|
|
Status = GetPrintJobId(Wait, InFsd, Irp, ICB_OF(IrpSp), InputBuffer, &InputBufferLength, OutputBuffer, OutputBufferLength);
|
|
Irp->IoStatus.Information = InputBufferLength;
|
|
break;
|
|
|
|
case FSCTL_LMR_GET_STATISTICS:
|
|
Status = GetStatistics(Wait, InFsd, Irp, ICB_OF(IrpSp), InputBuffer, &InputBufferLength, OutputBufferLength);
|
|
break;
|
|
|
|
case FSCTL_LMR_START_SMBTRACE:
|
|
Status = StartSmbTrace(Wait, InFsd, Irp, IrpSp, InputBuffer, InputBufferLength, OutputBufferLength);
|
|
break;
|
|
|
|
case FSCTL_LMR_END_SMBTRACE:
|
|
Status = StopSmbTrace(Wait, InFsd, Irp, IrpSp);
|
|
break;
|
|
|
|
case FSCTL_DFS_GET_REFERRALS:
|
|
Status = GetDfsReferral(
|
|
Irp,
|
|
ICB_OF(IrpSp),
|
|
InputBuffer,
|
|
InputBufferLength,
|
|
OutputBuffer,
|
|
OutputBufferLength);
|
|
break;
|
|
|
|
case FSCTL_DFS_REPORT_INCONSISTENCY:
|
|
Status = ReportDfsInconsistency(
|
|
Irp,
|
|
ICB_OF(IrpSp),
|
|
InputBuffer,
|
|
InputBufferLength);
|
|
break;
|
|
|
|
default:
|
|
|
|
// Everything else is remoted
|
|
|
|
//
|
|
// The following case selection is for any FSCTL
|
|
// not already handled. We will try to remote it.
|
|
//
|
|
|
|
|
|
|
|
if ((FsControlCode & 3) != METHOD_BUFFERED
|
|
|
|
&&
|
|
|
|
!InFsd) {
|
|
|
|
dprintf(DPRT_CAIRO, ("Irp is %08lx\n", Irp));
|
|
dprintf(DPRT_CAIRO, ("FsControlCode is %08lx\n", FsControlCode));
|
|
dprintf(DPRT_CAIRO, ("Attaching to process %08lx\n", IoGetRequestorProcess(Irp)));
|
|
|
|
KeAttachProcess(IoGetRequestorProcess(Irp));
|
|
fAttached = TRUE;
|
|
fHandledMethod3 = TRUE;
|
|
}
|
|
|
|
if (ICB_OF(IrpSp)->Fcb->Connection == NULL) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
|
|
} else {
|
|
|
|
//
|
|
// if NT server, send the FSCTL via NT TRANSACT
|
|
//
|
|
|
|
if (!Wait) {
|
|
ASSERT (InFsd);
|
|
dprintf(DPRT_CAIRO, ("Posting fsctl %08lx to FSP\n", FsControlCode));
|
|
Status = STATUS_PENDING;
|
|
} else {
|
|
dprintf(DPRT_CAIRO, ("Transacting fsctl %08lx\n", FsControlCode));
|
|
Status = RdrIssueNtIoctl(Wait,
|
|
InFsd,
|
|
Irp,
|
|
ICB_OF(IrpSp),
|
|
FsControlCode,
|
|
InputBuffer,
|
|
InputBufferLength,
|
|
OutputBuffer,
|
|
&OutputBufferLength);
|
|
|
|
Irp->IoStatus.Information = OutputBufferLength;
|
|
}
|
|
}
|
|
|
|
if (fAttached) {
|
|
dprintf(DPRT_CAIRO, ("Detaching process\n"));
|
|
KeDetachProcess();
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
} else {
|
|
Status = STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
} finally {
|
|
|
|
if (Status == STATUS_PENDING) {
|
|
|
|
ASSERT (InFsd);
|
|
|
|
|
|
if (fHandledMethod3) {
|
|
Status = STATUS_SUCCESS;
|
|
} else if ((FsControlCode & 3) == METHOD_NEITHER) {
|
|
Status = RdrConvertType3FsControlToType2FsControl(Irp, IrpSp);
|
|
}
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
Status = STATUS_PENDING;
|
|
RdrFsdPostToFsp(DeviceObject, Irp);
|
|
} else {
|
|
|
|
//
|
|
// We weren't able to set this up to be posted to the FSP.
|
|
// Complete the request with the appropriate error.
|
|
//
|
|
|
|
RdrCompleteRequest(Irp, Status);
|
|
}
|
|
} else {
|
|
|
|
RdrCompleteRequest(Irp, Status);
|
|
}
|
|
}
|
|
|
|
dprintf(DPRT_FSCTL, ("Returning status: %X\n", Status));
|
|
return Status;
|
|
}
|
|
|
|
DBGSTATIC
|
|
NTSTATUS
|
|
StartRedirector (
|
|
IN BOOLEAN Wait,
|
|
IN BOOLEAN InFsd,
|
|
IN PICB Icb,
|
|
IN PFS_DEVICE_OBJECT DeviceObject,
|
|
IN PLMR_REQUEST_PACKET InputBuffer,
|
|
IN ULONG InputBufferLength,
|
|
IN PWKSTA_INFO_502 WkstaBuffer,
|
|
IN ULONG OutputBufferLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine adds a reference to a file object created with .
|
|
|
|
Arguments:
|
|
|
|
IN BOOLEAN Wait, - True IFF redirector can block callers thread on request
|
|
IN BOOLEAN InFsd, - True IFF this request is initiated from the FSD.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
UNICODE_STRING ComputerName;
|
|
UNICODE_STRING DomainName;
|
|
BOOLEAN SmbExchangeInitialized = FALSE;
|
|
BOOLEAN SecurityInitialized = FALSE;
|
|
BOOLEAN TimerInitialized = FALSE;
|
|
|
|
PAGED_CODE();
|
|
|
|
UNREFERENCED_PARAMETER(Wait);
|
|
UNREFERENCED_PARAMETER(InFsd);
|
|
UNREFERENCED_PARAMETER(InputBufferLength);
|
|
|
|
// DbgBreakPoint();
|
|
|
|
|
|
dprintf(DPRT_FSCTL, ("NtFsControlFile: Initialize request "));
|
|
|
|
if (!ExAcquireResourceExclusive(&RdrDataResource, Wait)) {
|
|
return STATUS_PENDING;
|
|
}
|
|
|
|
RdrPrimaryDomain.Buffer = NULL;
|
|
RdrData.ComputerName = NULL;
|
|
RdrMupHandle = NULL;
|
|
|
|
try {
|
|
|
|
|
|
if (RdrData.Initialized == RdrStarted) {
|
|
dprintf(DPRT_FSCTL, ("Redirector already started\n"));
|
|
try_return(Status = STATUS_REDIRECTOR_STARTED);
|
|
}
|
|
|
|
if (Icb->Type != Redirector) {
|
|
try_return(Status = STATUS_INVALID_DEVICE_REQUEST);
|
|
}
|
|
|
|
//
|
|
// Load a pointer to the users input buffer into InputBuffer
|
|
//
|
|
|
|
if (InputBuffer->Version != REQUEST_PACKET_VERSION) {
|
|
try_return(Status = STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
if (InputBuffer->Type != ConfigInformation) {
|
|
try_return(Status = STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
if (InputBufferLength < sizeof(LMR_REQUEST_PACKET)) {
|
|
try_return(Status = STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
if (InputBufferLength < FIELD_OFFSET(LMR_REQUEST_PACKET, Parameters.Start.RedirectorName)+InputBuffer->Parameters.Start.RedirectorNameLength) {
|
|
try_return(Status = STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
if (OutputBufferLength != sizeof(WKSTA_INFO_502)) {
|
|
try_return(Status = STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
//
|
|
// We will fall over if we provide a value larger that a USHORT for
|
|
// this value, since we cannot pass it to servers...
|
|
//
|
|
|
|
if (WkstaBuffer->wki502_pipe_maximum == 0) {
|
|
try_return(Status = STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
if (WkstaBuffer->wki502_lock_maximum == 0) {
|
|
try_return(Status = STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
if (WkstaBuffer->wki502_dormant_file_limit == 0) {
|
|
try_return(Status = STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
//
|
|
// The security stuff has to be started in the FSP, so
|
|
// transition into the FSP if it's appropriate.
|
|
//
|
|
|
|
if (InFsd) {
|
|
try_return(Status = STATUS_PENDING);
|
|
}
|
|
|
|
RdrFspProcess = PsGetCurrentProcess();
|
|
|
|
//
|
|
// Initialize the size of the redirector SMB buffer cache and Mpx table.
|
|
//
|
|
|
|
MaximumCommands = (USHORT)WkstaBuffer->wki502_max_cmds;
|
|
|
|
//
|
|
// Initialize the dormant connection timeout value.
|
|
//
|
|
|
|
RdrData.DormantConnectionTimeout = WkstaBuffer->wki502_keep_conn;
|
|
|
|
//
|
|
// Initialize the backoff package initial values.
|
|
//
|
|
|
|
RdrData.LockIncrement = WkstaBuffer->wki502_lock_increment;
|
|
RdrData.LockMaximum = WkstaBuffer->wki502_lock_maximum;
|
|
|
|
RdrData.PipeIncrement = WkstaBuffer->wki502_pipe_increment;
|
|
RdrData.PipeMaximum = WkstaBuffer->wki502_pipe_maximum;
|
|
|
|
//
|
|
// Initialize the Byte mode, Named Pipe parameters
|
|
//
|
|
|
|
RdrData.PipeBufferSize = WkstaBuffer->wki502_siz_char_buf;
|
|
RdrData.MaximumCollectionCount = WkstaBuffer->wki502_maximum_collection_count;
|
|
RdrData.CollectDataTimeMs = WkstaBuffer->wki502_collection_time;
|
|
RdrData.PipeWaitTimeout = WkstaBuffer->wki502_char_wait;
|
|
|
|
//
|
|
// Initialize the lock&read quota.
|
|
//
|
|
|
|
RdrData.LockAndReadQuota = WkstaBuffer->wki502_lock_quota;
|
|
|
|
//
|
|
// Set the redirectors max # of threads.
|
|
//
|
|
|
|
RdrData.MaximumNumberOfThreads = WkstaBuffer->wki502_max_threads;
|
|
|
|
//
|
|
// Set the default session timeout.
|
|
//
|
|
|
|
RdrRequestTimeout = WkstaBuffer->wki502_sess_timeout;
|
|
|
|
//
|
|
// Set the cache dormant file timeout.
|
|
//
|
|
|
|
RdrData.CachedFileTimeout = WkstaBuffer->wki502_cache_file_timeout;
|
|
|
|
RdrData.DormantFileLimit = WkstaBuffer->wki502_dormant_file_limit;
|
|
|
|
//
|
|
// Readahead threshold
|
|
//
|
|
|
|
RdrData.ReadAheadThroughput = WkstaBuffer->wki502_read_ahead_throughput;
|
|
|
|
//
|
|
// Copy over the redirector workstation heuristics.
|
|
//
|
|
|
|
RdrData.UseOpportunisticLocking = (BOOLEAN )WkstaBuffer->wki502_use_opportunistic_locking;
|
|
RdrData.UseUnlockBehind = (BOOLEAN )WkstaBuffer->wki502_use_unlock_behind;
|
|
RdrData.UseCloseBehind = (BOOLEAN )WkstaBuffer->wki502_use_close_behind;
|
|
RdrData.BufferNamedPipes = (BOOLEAN )WkstaBuffer->wki502_buf_named_pipes;
|
|
RdrData.UseLockAndReadWriteAndUnlock = (BOOLEAN )WkstaBuffer->wki502_use_lock_read_unlock;
|
|
RdrData.UtilizeNtCaching = (BOOLEAN )WkstaBuffer->wki502_utilize_nt_caching;
|
|
RdrData.UseRawRead = (BOOLEAN )WkstaBuffer->wki502_use_raw_read;
|
|
RdrData.UseRawWrite = (BOOLEAN )WkstaBuffer->wki502_use_raw_write;
|
|
RdrData.UseWriteRawWithData = (BOOLEAN )WkstaBuffer->wki502_use_write_raw_data;
|
|
RdrData.UseEncryption = (BOOLEAN )WkstaBuffer->wki502_use_encryption;
|
|
RdrData.BufferFilesWithDenyWrite = (BOOLEAN )WkstaBuffer->wki502_buf_files_deny_write;
|
|
RdrData.BufferReadOnlyFiles = (BOOLEAN )WkstaBuffer->wki502_buf_read_only_files;
|
|
RdrData.ForceCoreCreateMode = (BOOLEAN )WkstaBuffer->wki502_force_core_create_mode;
|
|
RdrData.Use512ByteMaximumTransfer = (BOOLEAN )WkstaBuffer->wki502_use_512_byte_max_transfer;
|
|
|
|
//
|
|
// Now that we know what the user wants as the new maximum number
|
|
// of threads for the redirector's FSP, we can update the queue
|
|
// maximum.
|
|
//
|
|
|
|
RdrSetMaximumThreadsWorkQueue(&DeviceObject->IrpWorkQueue, RdrData.MaximumNumberOfThreads);
|
|
|
|
if (!NT_SUCCESS(Status = RdrpInitializeSmbExchange())) {
|
|
try_return(Status);
|
|
}
|
|
|
|
SmbExchangeInitialized = TRUE;
|
|
|
|
if (!NT_SUCCESS(Status = RdrpInitializeSecurity())) {
|
|
try_return(Status);
|
|
}
|
|
|
|
SecurityInitialized = TRUE;
|
|
|
|
//
|
|
// Initialize the redirector statistics.
|
|
//
|
|
|
|
RtlZeroMemory( &RdrStatistics, sizeof(RdrStatistics) );
|
|
|
|
KeQuerySystemTime(&RdrStatistics.StatisticsStartTime);
|
|
|
|
//
|
|
// Now that we know the dormant connection timeout, we can kick off the
|
|
// scavenger thread..
|
|
//
|
|
|
|
IoStartTimer((PDEVICE_OBJECT )DeviceObject);
|
|
|
|
TimerInitialized = TRUE;
|
|
|
|
RdrData.ComputerName = ALLOCATE_POOL(PagedPool, sizeof(TA_NETBIOS_ADDRESS)+NETBIOS_NAME_LEN, POOL_COMPUTERNAME);
|
|
|
|
if (RdrData.ComputerName == NULL) {
|
|
try_return(Status = STATUS_INSUFFICIENT_RESOURCES);
|
|
}
|
|
|
|
ComputerName.Length = (USHORT )InputBuffer->Parameters.Start.RedirectorNameLength;
|
|
ComputerName.MaximumLength = (USHORT )InputBuffer->Parameters.Start.RedirectorNameLength;
|
|
ComputerName.Buffer = InputBuffer->Parameters.Start.RedirectorName;
|
|
|
|
Status = RdrBuildNetbiosAddress((PTRANSPORT_ADDRESS)RdrData.ComputerName,
|
|
sizeof( TA_NETBIOS_ADDRESS ) + NETBIOS_NAME_LEN,
|
|
&ComputerName);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
try_return(Status);
|
|
}
|
|
|
|
//
|
|
// Stick the correct signature byte to the computer name.
|
|
//
|
|
|
|
RdrData.ComputerName->Address[0].Address[0].NetbiosName[NETBIOS_NAME_LEN-1] = '\0';
|
|
|
|
RdrPrimaryDomain.Buffer = ALLOCATE_POOL(PagedPool, InputBuffer->Parameters.Start.DomainNameLength, POOL_DOMAINNAME);
|
|
RdrPrimaryDomain.MaximumLength = (USHORT)InputBuffer->Parameters.Start.DomainNameLength;
|
|
|
|
if (RdrPrimaryDomain.Buffer == NULL) {
|
|
FREE_POOL(RdrData.ComputerName);
|
|
try_return(Status = STATUS_INSUFFICIENT_RESOURCES);
|
|
}
|
|
|
|
DomainName.Length = (USHORT)InputBuffer->Parameters.Start.DomainNameLength;
|
|
DomainName.MaximumLength = (USHORT)InputBuffer->Parameters.Start.DomainNameLength;
|
|
DomainName.Buffer = InputBuffer->Parameters.Start.RedirectorName+(InputBuffer->Parameters.Start.RedirectorNameLength/sizeof(WCHAR));
|
|
|
|
RtlCopyUnicodeString(&RdrPrimaryDomain, &DomainName);
|
|
|
|
Status = FsRtlRegisterUncProvider(
|
|
&RdrMupHandle,
|
|
&RdrNameString,
|
|
TRUE // Support mailslots
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
try_return(Status);
|
|
}
|
|
|
|
#ifdef RASAUTODIAL
|
|
//
|
|
// Bind with the automatic connection driver.
|
|
//
|
|
RdrAcdBind();
|
|
#endif // RASAUTODIAL
|
|
|
|
//
|
|
// Lastly, register with the security subsystem to notify us when
|
|
// logon sessions are terminated
|
|
//
|
|
|
|
SeRegisterLogonSessionTerminatedRoutine(
|
|
(PSE_LOGON_SESSION_TERMINATED_ROUTINE)
|
|
RdrHandleLogonSessionTermination);
|
|
|
|
RdrData.Initialized = RdrStarted;
|
|
|
|
try_return(Status = STATUS_SUCCESS);
|
|
try_exit:NOTHING;
|
|
|
|
} finally {
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
if (RdrMupHandle != NULL) {
|
|
FsRtlDeregisterUncProvider(RdrMupHandle);
|
|
}
|
|
|
|
if (RdrData.ComputerName != NULL) {
|
|
FREE_POOL(RdrData.ComputerName);
|
|
}
|
|
|
|
if (RdrPrimaryDomain.Buffer != NULL) {
|
|
FREE_POOL(RdrPrimaryDomain.Buffer);
|
|
}
|
|
if (TimerInitialized) {
|
|
IoStopTimer((PDEVICE_OBJECT )DeviceObject);
|
|
}
|
|
|
|
if (SecurityInitialized) {
|
|
RdrpUninitializeSecurity();
|
|
}
|
|
|
|
if (SmbExchangeInitialized) {
|
|
RdrpUninitializeSmbExchange();
|
|
}
|
|
|
|
}
|
|
|
|
ExReleaseResource(&RdrDataResource);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef RDR_PNP_POWER
|
|
|
|
DBGSTATIC
|
|
NTSTATUS
|
|
BindToTransport (
|
|
IN BOOLEAN Wait,
|
|
IN BOOLEAN InFsd,
|
|
IN PICB Icb,
|
|
IN PLMR_REQUEST_PACKET InputBuffer,
|
|
IN ULONG InputBufferLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine binds the NT to a transport provider.
|
|
|
|
Arguments:
|
|
|
|
IN BOOLEAN Wait, - True IFF redirector can block callers thread on request
|
|
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
UNICODE_STRING TransportName;
|
|
|
|
UNREFERENCED_PARAMETER(Wait);
|
|
UNREFERENCED_PARAMETER(InputBufferLength);
|
|
|
|
dprintf(DPRT_FSCTL, ("NtFsControlFile: Bind to transport "));
|
|
|
|
|
|
if (Icb->Type != Redirector) {
|
|
Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
goto ReturnStatus;
|
|
}
|
|
|
|
if (RdrData.Initialized != RdrStarted) {
|
|
dprintf(DPRT_FSCTL, ("Redirector not started.\n"));
|
|
Status = STATUS_REDIRECTOR_NOT_STARTED;
|
|
goto ReturnStatus;
|
|
}
|
|
|
|
//
|
|
// Check some fields in the input buffer.
|
|
//
|
|
|
|
if (InputBuffer->Version != REQUEST_PACKET_VERSION) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto ReturnStatus;
|
|
}
|
|
|
|
if (InputBufferLength < sizeof(LMR_REQUEST_PACKET)) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto ReturnStatus;
|
|
}
|
|
|
|
if (InputBufferLength < FIELD_OFFSET(LMR_REQUEST_PACKET, Parameters.Bind.TransportName)+InputBuffer->Parameters.Bind.TransportNameLength) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto ReturnStatus;
|
|
}
|
|
|
|
//
|
|
// We are about to perform the actual bind, if we cannot
|
|
// block the users thread, pass this request to the FSP
|
|
// to have it perform the operation.
|
|
//
|
|
|
|
if (InFsd) {
|
|
return STATUS_PENDING;
|
|
}
|
|
|
|
TransportName.MaximumLength = TransportName.Length = (USHORT )
|
|
InputBuffer->Parameters.Bind.TransportNameLength;
|
|
|
|
TransportName.Buffer = InputBuffer->Parameters.Bind.TransportName;
|
|
|
|
dprintf(DPRT_FSCTL, ("\"%wZ\"", &TransportName));
|
|
|
|
Status = RdrpTdiAllocateTransport(&TransportName,
|
|
InputBuffer->Parameters.Bind.QualityOfService);
|
|
|
|
ReturnStatus:
|
|
|
|
return Status;
|
|
}
|
|
|
|
#endif
|
|
|
|
DBGSTATIC
|
|
NTSTATUS
|
|
UnBindFromTransport (
|
|
IN BOOLEAN Wait,
|
|
IN BOOLEAN InFsd,
|
|
IN PIRP Irp,
|
|
IN PICB Icb,
|
|
IN PLMR_REQUEST_PACKET InputBuffer,
|
|
IN ULONG InputBufferLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sets the username for the NT redirector.
|
|
|
|
Arguments:
|
|
|
|
IN BOOLEAN Wait, - True IFF redirector can block callers thread on request
|
|
IN PFS_DEVICE_OBJECT DeviceObject, - Device object of destination of Irp
|
|
IN PIRP Irp, - Io Request Packet for request
|
|
IN PIO_STACK_LOCATION IrpSp - Current I/O Stack location for request
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
UNICODE_STRING TransportName;
|
|
PTRANSPORT Transport;
|
|
ULONG ForceLevel;
|
|
|
|
PAGED_CODE();
|
|
|
|
UNREFERENCED_PARAMETER(Wait);
|
|
UNREFERENCED_PARAMETER(InputBufferLength);
|
|
|
|
dprintf(DPRT_FSCTL, ("NtFsControlFile: Unbind from transport "));
|
|
|
|
if (Icb->Type != Redirector) {
|
|
Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
return Status;
|
|
}
|
|
|
|
if (RdrData.Initialized != RdrStarted) {
|
|
dprintf(DPRT_FSCTL, ("Redirector not started.\n"));
|
|
Status = STATUS_REDIRECTOR_NOT_STARTED;
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Check some fields in the input buffer.
|
|
//
|
|
|
|
if (InputBuffer->Version != REQUEST_PACKET_VERSION) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
return Status;
|
|
}
|
|
|
|
if (InputBufferLength < sizeof(LMR_REQUEST_PACKET)) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
return Status;
|
|
}
|
|
|
|
if (InputBufferLength < FIELD_OFFSET(LMR_REQUEST_PACKET, Parameters.Unbind.TransportName)+InputBuffer->Parameters.Unbind.TransportNameLength) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// We are about to perform the actual bind, if we cannot
|
|
// block the users thread, pass this request to the FSP
|
|
// to have it perform the operation.
|
|
//
|
|
|
|
if (InFsd) {
|
|
return STATUS_PENDING;
|
|
}
|
|
|
|
RdrReferenceDiscardableCode(RdrVCDiscardableSection);
|
|
ForceLevel = InputBuffer->Level;
|
|
|
|
TransportName.MaximumLength =
|
|
TransportName.Length =
|
|
(USHORT )InputBuffer->Parameters.Unbind.TransportNameLength;
|
|
|
|
TransportName.Buffer = InputBuffer->Parameters.Unbind.TransportName;
|
|
|
|
dprintf(DPRT_TRANSPORT, ("UnbindFromTransport: Call RdrFindTransport %wZ\n", &TransportName));
|
|
|
|
Transport = RdrFindTransport(&TransportName);
|
|
|
|
dprintf(DPRT_FSCTL, ("\"%wZ\"", &TransportName));
|
|
|
|
if (Transport == NULL) {
|
|
RdrDereferenceDiscardableCode(RdrVCDiscardableSection);
|
|
return STATUS_OBJECT_NAME_NOT_FOUND;
|
|
}
|
|
|
|
Status = RdrRemoveConnectionsTransport(Irp, Transport, ForceLevel);
|
|
|
|
//
|
|
// Remove the reference to the transport provider that was applied in
|
|
// RdrFindTransport.
|
|
//
|
|
|
|
dprintf(DPRT_TRANSPORT, ("UnbindFromTransport: Call RdrDereferenceTransport %lx\n", Transport));
|
|
|
|
Status = RdrDereferenceTransport(Transport->NonPagedTransport);
|
|
|
|
dprintf(DPRT_FSCTL, ("RdrUnbindFromTransport returning %X\n", Status));
|
|
|
|
RdrDereferenceDiscardableCode(RdrVCDiscardableSection);
|
|
return Status;
|
|
|
|
}
|
|
|
|
DBGSTATIC
|
|
NTSTATUS
|
|
EnumTransports (
|
|
IN BOOLEAN Wait,
|
|
IN BOOLEAN InFsd,
|
|
IN PICB Icb,
|
|
IN PLMR_REQUEST_PACKET InputBuffer,
|
|
IN OUT PULONG InputBufferLength,
|
|
IN PUCHAR OutputBuffer,
|
|
IN ULONG OutputBufferLength,
|
|
IN ULONG OutputBufferDisplacement
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sets the username for the NT redirector.
|
|
|
|
Arguments:
|
|
|
|
IN BOOLEAN Wait, - True IFF redirector can block callers thread on request
|
|
IN PFS_DEVICE_OBJECT DeviceObject, - Device object of destination of Irp
|
|
IN PIRP Irp, - Io Request Packet for request
|
|
IN PIO_STACK_LOCATION IrpSp - Current I/O Stack location for request
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
PAGED_CODE();
|
|
|
|
UNREFERENCED_PARAMETER(InFsd);
|
|
|
|
dprintf(DPRT_FSCTL, ("NtFsControlFile: Enumerate Transports "));
|
|
|
|
|
|
if (Icb->Type != Redirector) {
|
|
Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
return Status;
|
|
}
|
|
|
|
if (RdrData.Initialized != RdrStarted) {
|
|
dprintf(DPRT_FSCTL, ("Redirector not started.\n"));
|
|
Status = STATUS_REDIRECTOR_NOT_STARTED;
|
|
return Status;
|
|
}
|
|
|
|
if (*InputBufferLength < sizeof(LMR_REQUEST_PACKET)) {
|
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Check some fields in the input buffer.
|
|
//
|
|
|
|
if (InputBuffer->Version != REQUEST_PACKET_VERSION) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
return Status;
|
|
}
|
|
|
|
return RdrEnumerateTransports(Wait, InputBuffer, InputBufferLength, OutputBuffer, OutputBufferLength, OutputBufferDisplacement);
|
|
|
|
}
|
|
|
|
|
|
DBGSTATIC
|
|
NTSTATUS
|
|
SetConfigInfo (
|
|
IN BOOLEAN Wait,
|
|
IN BOOLEAN InFsd,
|
|
IN PICB Icb,
|
|
IN PFS_DEVICE_OBJECT DeviceObject,
|
|
IN PLMR_REQUEST_PACKET InputBuffer,
|
|
IN PULONG InputBufferLength,
|
|
IN PWKSTA_INFO_502 WkstaBuffer,
|
|
IN ULONG OutputBufferLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sets the username for the NT redirector.
|
|
|
|
Arguments:
|
|
|
|
IN BOOLEAN Wait, - True IFF redirector can block callers thread on request
|
|
IN PFS_DEVICE_OBJECT DeviceObject, - Device object of destination of Irp
|
|
IN PIRP Irp, - Io Request Packet for request
|
|
IN PIO_STACK_LOCATION IrpSp - Current I/O Stack location for request
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
PAGED_CODE();
|
|
|
|
UNREFERENCED_PARAMETER(InFsd);
|
|
|
|
dprintf(DPRT_FSCTL, ("NtFsControlFile: SetConfigInformation "));
|
|
|
|
if (!ExAcquireResourceExclusive(&RdrDataResource, Wait)) {
|
|
return (Status = STATUS_PENDING);
|
|
}
|
|
|
|
if (RdrData.Initialized != RdrStarted) {
|
|
dprintf(DPRT_FSCTL, ("Redirector not started.\n"));
|
|
|
|
Status = STATUS_REDIRECTOR_NOT_STARTED;
|
|
|
|
goto ReturnStatus;
|
|
}
|
|
|
|
if (Icb->Type != Redirector) {
|
|
Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
goto ReturnStatus;
|
|
}
|
|
|
|
|
|
//
|
|
// Load a pointer to the users input buffer into InputBuffer
|
|
//
|
|
|
|
if (InputBuffer->Version != REQUEST_PACKET_VERSION) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto ReturnStatus;
|
|
}
|
|
|
|
if (InputBuffer->Type != ConfigInformation) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto ReturnStatus;
|
|
}
|
|
|
|
if (*InputBufferLength < sizeof(LMR_REQUEST_PACKET) ||
|
|
OutputBufferLength < sizeof(WKSTA_INFO_502)) {
|
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|
goto ReturnStatus;
|
|
}
|
|
|
|
*InputBufferLength = sizeof(LMR_REQUEST_PACKET);
|
|
|
|
//
|
|
// Now that we know what the user wants as the new maximum number
|
|
// of threads for the redirector's FSP, we can update the queue
|
|
// maximum.
|
|
//
|
|
|
|
RdrSetMaximumThreadsWorkQueue(&DeviceObject->IrpWorkQueue, WkstaBuffer->wki502_max_threads);
|
|
|
|
//
|
|
// Otherwise, update the relevant information.
|
|
//
|
|
|
|
RdrData.DormantConnectionTimeout = WkstaBuffer->wki502_keep_conn;
|
|
|
|
//
|
|
// Return the backoff package values.
|
|
//
|
|
|
|
RdrData.LockIncrement = WkstaBuffer->wki502_lock_increment;
|
|
RdrData.LockMaximum = WkstaBuffer->wki502_lock_maximum;
|
|
|
|
RdrData.PipeIncrement = WkstaBuffer->wki502_pipe_increment;
|
|
RdrData.PipeMaximum = WkstaBuffer->wki502_pipe_maximum;
|
|
|
|
//
|
|
// Return the byte mode, Named Pipe parameters
|
|
//
|
|
|
|
RdrData.MaximumCollectionCount = WkstaBuffer->wki502_maximum_collection_count;
|
|
RdrData.CollectDataTimeMs = WkstaBuffer->wki502_collection_time;
|
|
RdrData.PipeBufferSize = WkstaBuffer->wki502_siz_char_buf;
|
|
RdrData.PipeWaitTimeout = WkstaBuffer->wki502_char_wait;
|
|
|
|
//
|
|
// Set a new value for Lock&Read Quota and Raw Read threshold.
|
|
//
|
|
|
|
RdrData.LockAndReadQuota = WkstaBuffer->wki502_lock_quota;
|
|
|
|
RdrData.MaximumNumberOfThreads = WkstaBuffer->wki502_max_threads;
|
|
|
|
//
|
|
// Set the default session timeout.
|
|
//
|
|
|
|
RdrRequestTimeout = WkstaBuffer->wki502_sess_timeout;
|
|
|
|
//
|
|
// Set the cache dormant file timeout.
|
|
//
|
|
|
|
RdrData.CachedFileTimeout = WkstaBuffer->wki502_cache_file_timeout;
|
|
|
|
RdrData.DormantFileLimit = WkstaBuffer->wki502_dormant_file_limit;
|
|
|
|
//
|
|
// Copy the redirector heuristics.
|
|
//
|
|
|
|
RdrData.UseOpportunisticLocking = (BOOLEAN )WkstaBuffer->wki502_use_opportunistic_locking;
|
|
RdrData.UseUnlockBehind = (BOOLEAN )WkstaBuffer->wki502_use_unlock_behind;
|
|
RdrData.UseCloseBehind = (BOOLEAN )WkstaBuffer->wki502_use_close_behind;
|
|
RdrData.BufferNamedPipes = (BOOLEAN )WkstaBuffer->wki502_buf_named_pipes;
|
|
RdrData.UseLockAndReadWriteAndUnlock = (BOOLEAN )WkstaBuffer->wki502_use_lock_read_unlock;
|
|
RdrData.UtilizeNtCaching = (BOOLEAN )WkstaBuffer->wki502_utilize_nt_caching;
|
|
RdrData.UseRawRead = (BOOLEAN )WkstaBuffer->wki502_use_raw_read;
|
|
RdrData.UseRawWrite = (BOOLEAN )WkstaBuffer->wki502_use_raw_write;
|
|
RdrData.UseWriteRawWithData = (BOOLEAN )WkstaBuffer->wki502_use_write_raw_data;
|
|
RdrData.UseEncryption = (BOOLEAN )WkstaBuffer->wki502_use_encryption;
|
|
RdrData.BufferFilesWithDenyWrite = (BOOLEAN )WkstaBuffer->wki502_buf_files_deny_write;
|
|
RdrData.BufferReadOnlyFiles = (BOOLEAN )WkstaBuffer->wki502_buf_read_only_files;
|
|
RdrData.ForceCoreCreateMode = (BOOLEAN )WkstaBuffer->wki502_force_core_create_mode;
|
|
RdrData.Use512ByteMaximumTransfer = (BOOLEAN )WkstaBuffer->wki502_use_512_byte_max_transfer;
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
ReturnStatus:
|
|
|
|
ExReleaseResource(&RdrDataResource);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
DBGSTATIC
|
|
NTSTATUS
|
|
GetConfigInfo (
|
|
IN BOOLEAN Wait,
|
|
IN BOOLEAN InFsd,
|
|
IN PICB Icb,
|
|
IN PLMR_REQUEST_PACKET InputBuffer,
|
|
IN OUT PULONG InputBufferLength,
|
|
IN PWKSTA_INFO_502 WkstaBuffer,
|
|
IN ULONG OutputBufferLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sets the username for the NT redirector.
|
|
|
|
Arguments:
|
|
|
|
IN BOOLEAN Wait, - True IFF redirector can block callers thread on request
|
|
IN PFS_DEVICE_OBJECT DeviceObject, - Device object of destination of Irp
|
|
IN PIRP Irp, - Io Request Packet for request
|
|
IN PIO_STACK_LOCATION IrpSp - Current I/O Stack location for request
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
PAGED_CODE();
|
|
|
|
UNREFERENCED_PARAMETER(InFsd);
|
|
|
|
dprintf(DPRT_FSCTL, ("NtFsControlFile: GetConfigInfo "));
|
|
|
|
if (!ExAcquireResourceShared(&RdrDataResource, Wait)) {
|
|
Status = STATUS_PENDING;
|
|
goto ReturnStatus;
|
|
}
|
|
|
|
if (Icb->Type != Redirector) {
|
|
Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
goto ReturnStatus;
|
|
}
|
|
|
|
|
|
if (RdrData.Initialized != RdrStarted) {
|
|
dprintf(DPRT_FSCTL, ("Redirector not started.\n"));
|
|
Status = STATUS_REDIRECTOR_NOT_STARTED;
|
|
goto ReturnStatus;
|
|
}
|
|
|
|
if (InputBuffer->Version != REQUEST_PACKET_VERSION) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto ReturnStatus;
|
|
}
|
|
|
|
if (InputBuffer->Type != ConfigInformation) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto ReturnStatus;
|
|
}
|
|
|
|
if (*InputBufferLength < sizeof(LMR_REQUEST_PACKET) ||
|
|
OutputBufferLength < sizeof(WKSTA_INFO_502)) {
|
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|
goto ReturnStatus;
|
|
}
|
|
|
|
try {
|
|
//
|
|
// Return general configuration stuff.
|
|
//
|
|
|
|
WkstaBuffer->wki502_keep_conn = RdrData.DormantConnectionTimeout;
|
|
|
|
WkstaBuffer->wki502_max_cmds = (ULONG)MaximumCommands;
|
|
|
|
WkstaBuffer->wki502_max_threads = RdrData.MaximumNumberOfThreads;
|
|
|
|
//
|
|
// Return the backoff package values.
|
|
//
|
|
|
|
WkstaBuffer->wki502_lock_increment = RdrData.LockIncrement;
|
|
WkstaBuffer->wki502_lock_maximum = RdrData.LockMaximum;
|
|
|
|
WkstaBuffer->wki502_pipe_increment = RdrData.PipeIncrement;
|
|
WkstaBuffer->wki502_pipe_maximum = RdrData.PipeMaximum;
|
|
|
|
//
|
|
// Return the byte mode, Named Pipe parameters
|
|
//
|
|
|
|
WkstaBuffer->wki502_siz_char_buf = RdrData.PipeBufferSize;
|
|
WkstaBuffer->wki502_maximum_collection_count = RdrData.MaximumCollectionCount;
|
|
WkstaBuffer->wki502_collection_time = RdrData.CollectDataTimeMs;
|
|
WkstaBuffer->wki502_char_wait = RdrData.PipeWaitTimeout;
|
|
|
|
//
|
|
// Initialize the lock&read quota.
|
|
//
|
|
|
|
WkstaBuffer->wki502_lock_quota = RdrData.LockAndReadQuota;
|
|
|
|
WkstaBuffer->wki502_cache_file_timeout = RdrData.CachedFileTimeout;
|
|
|
|
WkstaBuffer->wki502_dormant_file_limit = RdrData.DormantFileLimit;
|
|
|
|
WkstaBuffer->wki502_sess_timeout = RdrRequestTimeout;
|
|
|
|
WkstaBuffer->wki502_read_ahead_throughput = RdrData.ReadAheadThroughput;
|
|
|
|
//
|
|
// Copy the redirector heuristics.
|
|
//
|
|
|
|
WkstaBuffer->wki502_use_opportunistic_locking = RdrData.UseOpportunisticLocking;
|
|
WkstaBuffer->wki502_use_unlock_behind = RdrData.UseUnlockBehind;
|
|
WkstaBuffer->wki502_use_close_behind = RdrData.UseCloseBehind;
|
|
WkstaBuffer->wki502_buf_named_pipes = RdrData.BufferNamedPipes;
|
|
WkstaBuffer->wki502_use_lock_read_unlock = RdrData.UseLockAndReadWriteAndUnlock;
|
|
WkstaBuffer->wki502_utilize_nt_caching = RdrData.UtilizeNtCaching;
|
|
WkstaBuffer->wki502_use_raw_read = RdrData.UseRawRead;
|
|
WkstaBuffer->wki502_use_raw_write = RdrData.UseRawWrite;
|
|
WkstaBuffer->wki502_use_write_raw_data = RdrData.UseWriteRawWithData;
|
|
WkstaBuffer->wki502_use_encryption = RdrData.UseEncryption;
|
|
WkstaBuffer->wki502_buf_files_deny_write = RdrData.BufferFilesWithDenyWrite;
|
|
WkstaBuffer->wki502_buf_read_only_files = RdrData.BufferReadOnlyFiles;
|
|
WkstaBuffer->wki502_force_core_create_mode = RdrData.ForceCoreCreateMode;
|
|
WkstaBuffer->wki502_use_512_byte_max_transfer = RdrData.Use512ByteMaximumTransfer;
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
Status = GetExceptionCode();
|
|
goto ReturnStatus;
|
|
}
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
ReturnStatus:
|
|
if (Status != STATUS_PENDING) {
|
|
|
|
try {
|
|
InputBuffer->Parameters.Get.EntriesRead = 1;
|
|
InputBuffer->Parameters.Get.TotalEntries = 1;
|
|
InputBuffer->Parameters.Get.TotalBytesNeeded = sizeof(WKSTA_INFO_502);
|
|
|
|
*InputBufferLength = sizeof(LMR_REQUEST_PACKET);
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
Status = GetExceptionCode();
|
|
}
|
|
|
|
ExReleaseResource(&RdrDataResource);
|
|
}
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
DBGSTATIC
|
|
NTSTATUS
|
|
GetConnectInfo (
|
|
IN BOOLEAN Wait,
|
|
IN BOOLEAN InFsd,
|
|
IN PICB Icb,
|
|
IN PLMR_REQUEST_PACKET InputBuffer,
|
|
IN OUT PULONG InputBufferLength,
|
|
IN PUCHAR OutputBuffer,
|
|
IN ULONG OutputBufferLength,
|
|
IN ULONG OutputBufferDisplacement
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns connection information about a given tree connection
|
|
|
|
Arguments:
|
|
|
|
IN BOOLEAN Wait, - True IFF redirector can block callers thread on request
|
|
IN PFS_DEVICE_OBJECT DeviceObject, - Device object of destination of Irp
|
|
IN PIRP Irp, - Io Request Packet for request
|
|
IN PIO_STACK_LOCATION IrpSp - Current I/O Stack location for request
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
Note:
|
|
This is a synchronous API.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
PFCB TreeConnectFcb;
|
|
PCONNECTLISTENTRY Cle;
|
|
PUCHAR OutputBufferSave = OutputBuffer;
|
|
PUCHAR OutputBufferEnd;
|
|
// LUID LogonId;
|
|
|
|
PAGED_CODE();
|
|
|
|
UNREFERENCED_PARAMETER(Wait);
|
|
UNREFERENCED_PARAMETER(InFsd);
|
|
|
|
dprintf(DPRT_FSCTL, ("NtFsControlFile: GetConnectInfo "));
|
|
|
|
TreeConnectFcb = Icb->Fcb;
|
|
|
|
if (!(Icb->Flags & ICB_TCONCREATED)) {
|
|
return Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
}
|
|
|
|
|
|
if (RdrData.Initialized != RdrStarted) {
|
|
dprintf(DPRT_FSCTL, ("Redirector not started.\n"));
|
|
return Status = STATUS_REDIRECTOR_NOT_STARTED;
|
|
}
|
|
|
|
try {
|
|
|
|
//
|
|
// Load a pointer to the users input buffer into InputBuffer
|
|
//
|
|
|
|
if (InputBuffer->Version != REQUEST_PACKET_VERSION) {
|
|
return(Status = STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
if (InputBuffer->Level == 0) {
|
|
if ( OutputBufferLength < sizeof(LMR_CONNECTION_INFO_0)) {
|
|
return(Status = STATUS_BUFFER_TOO_SMALL);
|
|
}
|
|
} else if (InputBuffer->Level == 1) {
|
|
if (OutputBufferLength < sizeof(LMR_CONNECTION_INFO_1)) {
|
|
return(Status = STATUS_BUFFER_TOO_SMALL);
|
|
}
|
|
} else if (InputBuffer->Level == 2) {
|
|
if (OutputBufferLength < sizeof(LMR_CONNECTION_INFO_2)) {
|
|
return(Status = STATUS_BUFFER_TOO_SMALL);
|
|
}
|
|
} else if (InputBuffer->Level == 3) {
|
|
if (OutputBufferLength < sizeof(LMR_CONNECTION_INFO_3)) {
|
|
return(Status = STATUS_BUFFER_TOO_SMALL);
|
|
}
|
|
} else {
|
|
return(Status = STATUS_INVALID_INFO_CLASS);
|
|
}
|
|
|
|
OutputBufferEnd = ((PUCHAR)OutputBuffer)+OutputBufferLength;
|
|
|
|
Cle = TreeConnectFcb->Connection;
|
|
|
|
InputBuffer->Parameters.Get.TotalEntries = 1;
|
|
|
|
InputBuffer->Parameters.Get.TotalBytesNeeded = 0;
|
|
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
return GetExceptionCode();
|
|
|
|
}
|
|
|
|
try {
|
|
RdrReferenceDiscardableCode(RdrFileDiscardableSection);
|
|
|
|
try {
|
|
PSECURITY_ENTRY DefaultSe = NULL;
|
|
|
|
if (PackConnectEntry(InputBuffer->Level,
|
|
&OutputBuffer,
|
|
&OutputBufferEnd,
|
|
OutputBufferDisplacement,
|
|
&Icb->DeviceName,
|
|
Cle,
|
|
Icb->Se,
|
|
&InputBuffer->Parameters.Get.TotalBytesNeeded)) {
|
|
|
|
InputBuffer->Parameters.Get.EntriesRead = 1;
|
|
}
|
|
|
|
if (InputBuffer->Level >= 2) {
|
|
|
|
//
|
|
// If the ICB has a security entry, use that
|
|
//
|
|
|
|
if (Icb->Se != NULL) {
|
|
|
|
//
|
|
// If we were able to find a security entry on the
|
|
// connection for the currently logged on user, copy
|
|
// the session key from the security entry to the buffer.
|
|
//
|
|
|
|
RtlCopyMemory(
|
|
((PLMR_CONNECTION_INFO_2)OutputBufferSave)->UserSessionKey,
|
|
Icb->Se->UserSessionKey,
|
|
MSV1_0_USER_SESSION_KEY_LENGTH);
|
|
|
|
RtlCopyMemory(
|
|
((PLMR_CONNECTION_INFO_2)OutputBufferSave)->LanmanSessionKey,
|
|
Icb->Se->LanmanSessionKey,
|
|
MSV1_0_LANMAN_SESSION_KEY_LENGTH);
|
|
|
|
try_return(Status = STATUS_SUCCESS);
|
|
|
|
} else {
|
|
try_return(Status = STATUS_NO_SUCH_LOGON_SESSION);
|
|
}
|
|
}
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
try_return(Status = GetExceptionCode());
|
|
}
|
|
|
|
*InputBufferLength = sizeof(LMR_REQUEST_PACKET);
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
try_return(Status);
|
|
|
|
try_exit:NOTHING;
|
|
} finally {
|
|
if (!NT_SUCCESS(Status)) {
|
|
*InputBufferLength = 0;
|
|
}
|
|
|
|
RdrDereferenceDiscardableCode(RdrFileDiscardableSection);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
DBGSTATIC
|
|
NTSTATUS
|
|
EnumerateConnections (
|
|
IN BOOLEAN Wait,
|
|
IN BOOLEAN InFsd,
|
|
IN PIRP Irp,
|
|
IN PICB Icb,
|
|
IN PLMR_REQUEST_PACKET InputBuffer,
|
|
IN OUT PULONG InputBufferLength,
|
|
IN PUCHAR OutputBuffer,
|
|
IN ULONG OutputBufferLength,
|
|
IN ULONG OutputBufferDisplacement
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sets the username for the NT redirector.
|
|
|
|
Arguments:
|
|
|
|
IN BOOLEAN Wait, - True IFF redirector can block callers thread on request
|
|
IN PFS_DEVICE_OBJECT DeviceObject, - Device object of destination of Irp
|
|
IN PIRP Irp, - Io Request Packet for request
|
|
IN PIO_STACK_LOCATION IrpSp - Current I/O Stack location for request
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
BOOLEAN ConnectDatabaseLocked = FALSE;
|
|
PUCHAR OutputBufferEnd;
|
|
ULONG Level;
|
|
PSECURITY_ENTRY Se = NULL;
|
|
LUID LogonId;
|
|
PLIST_ENTRY NextServer;
|
|
|
|
PAGED_CODE();
|
|
|
|
UNREFERENCED_PARAMETER(InFsd);
|
|
|
|
dprintf(DPRT_FSCTL, ("NtFsControlFile: EnumerateConnections "));
|
|
|
|
try {
|
|
PLIST_ENTRY ServerEntry;
|
|
|
|
RdrReferenceDiscardableCode(RdrFileDiscardableSection);
|
|
|
|
if (Icb->Type != Redirector) {
|
|
try_return(Status = STATUS_INVALID_DEVICE_REQUEST);
|
|
}
|
|
|
|
if (RdrData.Initialized != RdrStarted) {
|
|
dprintf(DPRT_FSCTL, ("Redirector not started.\n"));
|
|
try_return(Status = STATUS_REDIRECTOR_NOT_STARTED);
|
|
}
|
|
|
|
//
|
|
// Load a pointer to the users input buffer into InputBuffer.
|
|
//
|
|
// If the request has been passed to the FSP, the input buffer
|
|
// will be in AssociatedIrp.SystemBuffer, otherwise it will
|
|
// be in the Type3InputBuffer.
|
|
//
|
|
|
|
if (*InputBufferLength < sizeof(LMR_REQUEST_PACKET)) {
|
|
try_return(Status = STATUS_BUFFER_TOO_SMALL);
|
|
}
|
|
|
|
if (InputBuffer->Version != REQUEST_PACKET_VERSION) {
|
|
try_return(Status = STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
if (InputBuffer->Level == 0) {
|
|
if ( OutputBufferLength < sizeof(LMR_CONNECTION_INFO_0)) {
|
|
try_return(Status = STATUS_BUFFER_TOO_SMALL);
|
|
}
|
|
} else if (InputBuffer->Level == 1) {
|
|
if (OutputBufferLength < sizeof(LMR_CONNECTION_INFO_1)) {
|
|
try_return(Status = STATUS_BUFFER_TOO_SMALL);
|
|
}
|
|
} else if (InputBuffer->Level == 2) {
|
|
if (OutputBufferLength < sizeof(LMR_CONNECTION_INFO_2)) {
|
|
try_return(Status = STATUS_BUFFER_TOO_SMALL);
|
|
}
|
|
} else if (InputBuffer->Level == 3) {
|
|
if (OutputBufferLength < sizeof(LMR_CONNECTION_INFO_3)) {
|
|
try_return(Status = STATUS_BUFFER_TOO_SMALL);
|
|
}
|
|
} else {
|
|
try_return(Status = STATUS_INVALID_INFO_CLASS);
|
|
}
|
|
|
|
Status = KeWaitForMutexObject(&RdrDatabaseMutex,
|
|
Executive, KernelMode, FALSE, (Wait ? NULL : &RdrZero));
|
|
|
|
if (Status == STATUS_TIMEOUT) {
|
|
try_return(Status = STATUS_PENDING);
|
|
|
|
}
|
|
|
|
ASSERT (NT_SUCCESS(Status));
|
|
|
|
ConnectDatabaseLocked = TRUE;
|
|
|
|
try {
|
|
InputBuffer->Parameters.Get.EntriesRead = 0;
|
|
InputBuffer->Parameters.Get.TotalEntries = 0;
|
|
InputBuffer->Parameters.Get.TotalBytesNeeded = 0;
|
|
Level = InputBuffer->Level;
|
|
RtlCopyLuid(&LogonId, &InputBuffer->LogonId);
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
try_return(Status = GetExceptionCode());
|
|
}
|
|
|
|
OutputBufferEnd = ((PUCHAR)OutputBuffer)+OutputBufferLength;
|
|
|
|
for (ServerEntry = RdrServerHead.Flink ;
|
|
ServerEntry != &RdrServerHead ;
|
|
ServerEntry = NextServer) {
|
|
|
|
PSERVERLISTENTRY Sle = CONTAINING_RECORD(ServerEntry, SERVERLISTENTRY, GlobalNext);
|
|
PLIST_ENTRY ConnectEntry, NextConnection;
|
|
|
|
ASSERT (ConnectDatabaseLocked);
|
|
|
|
ASSERT(Sle->Signature == STRUCTURE_SIGNATURE_SERVERLISTENTRY);
|
|
|
|
//
|
|
// Reference the server list entry to make sure that we can
|
|
// release the database mutex without blowing up our chain.
|
|
//
|
|
|
|
RdrReferenceServer(Sle);
|
|
|
|
KeReleaseMutex(&RdrDatabaseMutex, FALSE);
|
|
|
|
ConnectDatabaseLocked = FALSE;
|
|
|
|
//
|
|
// If we cannot find a security entry for this user, we want to
|
|
// skip over this server.
|
|
//
|
|
// We want to check both the primary connection and the special
|
|
// IPC connection.
|
|
//
|
|
|
|
//
|
|
// We cannot call RdrFindSecurityEntry while we hold the
|
|
// database mutex.
|
|
//
|
|
|
|
if ((Se = RdrFindSecurityEntry(NULL, Sle, &LogonId, NULL)) == NULL) {
|
|
|
|
//
|
|
// Re-acquire the database mutex before we go back
|
|
// to get the next server.
|
|
//
|
|
|
|
Status = KeWaitForMutexObject(&RdrDatabaseMutex, Executive,
|
|
KernelMode, FALSE, NULL);
|
|
|
|
ConnectDatabaseLocked = TRUE;
|
|
|
|
ASSERT ( Sle->GlobalNext.Flink == ServerEntry->Flink );
|
|
|
|
NextServer = Sle->GlobalNext.Flink;
|
|
|
|
RdrDereferenceServer(Irp, Sle);
|
|
|
|
continue;
|
|
}
|
|
|
|
Status = KeWaitForMutexObject(&RdrDatabaseMutex,
|
|
Executive, KernelMode, FALSE, (Wait ? NULL : &RdrZero));
|
|
|
|
if (Status == STATUS_TIMEOUT) {
|
|
|
|
//
|
|
// Dereference the server before we return.
|
|
//
|
|
|
|
RdrDereferenceServer(Irp, Sle);
|
|
|
|
try_return(Status = STATUS_PENDING);
|
|
}
|
|
|
|
ASSERT (NT_SUCCESS(Status));
|
|
|
|
ConnectDatabaseLocked = TRUE;
|
|
|
|
for (ConnectEntry = Sle->CLEHead.Flink ;
|
|
ConnectEntry != &Sle->CLEHead ;
|
|
ConnectEntry = NextConnection) {
|
|
PCONNECTLISTENTRY Cle = CONTAINING_RECORD(ConnectEntry, CONNECTLISTENTRY, SiblingNext);
|
|
|
|
ASSERT(Cle->Signature == STRUCTURE_SIGNATURE_CONNECTLISTENTRY);
|
|
|
|
//
|
|
// Reference the connection while we release the mutex.
|
|
//
|
|
|
|
RdrReferenceConnection(Cle);
|
|
|
|
//
|
|
// Release the database mutex while packing the entry.
|
|
//
|
|
// We need to do this because PackConnectEntry will call
|
|
// RdrCopyUserName which will call RdrGetUserName which
|
|
// will call KeAttachProcess to attach to the redir FSP.
|
|
// You cannot attach to a process while owning a mutex,
|
|
// so......
|
|
//
|
|
|
|
KeReleaseMutex(&RdrDatabaseMutex, FALSE);
|
|
|
|
ConnectDatabaseLocked = FALSE;
|
|
|
|
try {
|
|
ULONG ResumeHandle = InputBuffer->Parameters.Get.ResumeHandle;
|
|
|
|
if (Cle->SerialNumber > ResumeHandle) {
|
|
ULONG NumberOfTreeConnections;
|
|
RdrGetConnectionReferences(
|
|
Cle,
|
|
NULL,
|
|
Se,
|
|
&NumberOfTreeConnections,
|
|
NULL,
|
|
NULL
|
|
);
|
|
if (NumberOfTreeConnections == 0) {
|
|
PSECURITY_ENTRY DefaultSe = NULL;
|
|
|
|
DefaultSe = RdrFindDefaultSecurityEntry(Cle, &LogonId);
|
|
|
|
InputBuffer->Parameters.Get.TotalEntries ++ ;
|
|
|
|
if (PackConnectEntry(Level,
|
|
&OutputBuffer,
|
|
&OutputBufferEnd,
|
|
OutputBufferDisplacement,
|
|
&Icb->DeviceName,
|
|
Cle,
|
|
(DefaultSe != NULL ?
|
|
DefaultSe :
|
|
Se),
|
|
&InputBuffer->Parameters.Get.TotalBytesNeeded)) {
|
|
InputBuffer->Parameters.Get.EntriesRead ++ ;
|
|
}
|
|
|
|
if (DefaultSe != NULL) {
|
|
RdrDereferenceSecurityEntry(DefaultSe->NonPagedSecurityEntry);
|
|
}
|
|
}
|
|
}
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
//
|
|
// Remove the reference to the connection applied above.
|
|
//
|
|
|
|
RdrDereferenceConnection(Irp, Cle, NULL, FALSE);
|
|
|
|
//
|
|
// Remove the reference to the server applied above.
|
|
//
|
|
|
|
RdrDereferenceServer(Irp, Sle);
|
|
|
|
try_return(Status = GetExceptionCode());
|
|
}
|
|
|
|
//
|
|
// Step to the next connection.
|
|
//
|
|
|
|
if (!NT_SUCCESS(KeWaitForMutexObject(&RdrDatabaseMutex, // Object to wait.
|
|
Executive, // Reason for waiting
|
|
KernelMode, // Processor mode
|
|
FALSE, // Alertable
|
|
NULL))) {
|
|
InternalError(("Unable to claim connection mutex in GetConnection"));
|
|
}
|
|
|
|
ConnectDatabaseLocked = TRUE;
|
|
|
|
//
|
|
// Now make the connection go away (with extreme prejudice)
|
|
//
|
|
|
|
NextConnection = ConnectEntry->Flink;
|
|
|
|
//
|
|
// Please note that this may make the connectlistentry
|
|
// go away if there are no other references to the
|
|
// connection.
|
|
//
|
|
// We do not forcably delete this connection, since it
|
|
// may already be dormant.
|
|
//
|
|
|
|
RdrDereferenceConnection(Irp, Cle, Se, FALSE);
|
|
|
|
}
|
|
|
|
ASSERT (ConnectDatabaseLocked);
|
|
|
|
RdrDereferenceSecurityEntry(Se->NonPagedSecurityEntry);
|
|
|
|
NextServer = Sle->GlobalNext.Flink;
|
|
|
|
RdrDereferenceServer(Irp, Sle);
|
|
|
|
}
|
|
|
|
Se = NULL;
|
|
|
|
*InputBufferLength = sizeof(LMR_REQUEST_PACKET);
|
|
|
|
//
|
|
// It's possible we didn't fit all the entries into the buffer that
|
|
// the workstation requested. If that is the case, then
|
|
// indicate it.
|
|
//
|
|
|
|
if (InputBuffer->Parameters.Get.EntriesRead != InputBuffer->Parameters.Get.TotalEntries) {
|
|
try_return(Status = STATUS_MORE_ENTRIES);
|
|
}
|
|
|
|
try_return(Status = STATUS_SUCCESS);
|
|
|
|
try_exit:NOTHING;
|
|
} finally {
|
|
|
|
if (Se != NULL) {
|
|
RdrDereferenceSecurityEntry(Se->NonPagedSecurityEntry);
|
|
}
|
|
|
|
if (ConnectDatabaseLocked) {
|
|
KeReleaseMutex(&RdrDatabaseMutex, FALSE);
|
|
}
|
|
|
|
RdrDereferenceDiscardableCode(RdrFileDiscardableSection);
|
|
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
DBGSTATIC
|
|
NTSTATUS
|
|
UserTransaction (
|
|
IN BOOLEAN Wait,
|
|
IN BOOLEAN InFsd,
|
|
IN PIRP Irp,
|
|
IN PICB Icb,
|
|
IN PLMR_TRANSACTION InputBuffer,
|
|
IN OUT PULONG InputBufferLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine exchanges information with the remote server.
|
|
|
|
Arguments:
|
|
|
|
IN BOOLEAN Wait, - True IFF redirector can block callers thread on request
|
|
IN PFS_DEVICE_OBJECT DeviceObject, - Device object of destination of Irp
|
|
IN PIRP Irp, - Io Request Packet for request
|
|
IN PIO_STACK_LOCATION IrpSp - Current I/O Stack location for request
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Status of transaction operation.
|
|
|
|
|
|
Note:
|
|
This API is a SYNCHRONOUS API. We will lock up the users thread regardless
|
|
of whether or not the request was actually synchronous.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
BOOLEAN ResourceAcquired = FALSE;
|
|
UNICODE_STRING TransactionName;
|
|
|
|
PAGED_CODE();
|
|
|
|
UNREFERENCED_PARAMETER(Wait);
|
|
UNREFERENCED_PARAMETER(InFsd);
|
|
|
|
try {
|
|
if ((InputBuffer->Type != TRANSACTION_REQUEST) ||
|
|
(InputBuffer->Version != TRANSACTION_VERSION)) {
|
|
try_return(Status = STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
if (*InputBufferLength < sizeof(LMR_TRANSACTION)) {
|
|
try_return(Status = STATUS_BUFFER_TOO_SMALL);
|
|
}
|
|
|
|
if (RdrData.Initialized != RdrStarted) {
|
|
try_return(Status = STATUS_REDIRECTOR_NOT_STARTED);
|
|
}
|
|
|
|
if (Icb->Fcb->Connection->Type != ServerRoot &&
|
|
Icb->Fcb->Connection->Server->Capabilities & DF_LANMAN10 ) {
|
|
try_return(Status = STATUS_NOT_SUPPORTED);
|
|
}
|
|
|
|
RdrReferenceDiscardableCode(RdrFileDiscardableSection);
|
|
|
|
TransactionName.MaximumLength = (USHORT )InputBuffer->NameLength;
|
|
TransactionName.Length = (USHORT )InputBuffer->NameLength;
|
|
TransactionName.Buffer = (PWSTR )(((PUCHAR)InputBuffer)+InputBuffer->NameOffset);
|
|
|
|
Status = RdrTransact(Irp, Icb->Fcb->Connection, Icb->Se,
|
|
(PUCHAR)InputBuffer+InputBuffer->SetupOffset,
|
|
InputBuffer->SetupWords,
|
|
&InputBuffer->MaxSetup,
|
|
&TransactionName,
|
|
InputBuffer->ParmPtr,
|
|
InputBuffer->ParmLength,
|
|
&InputBuffer->MaxRetParmLength,
|
|
InputBuffer->DataPtr,
|
|
InputBuffer->DataLength,
|
|
InputBuffer->RetDataPtr,
|
|
&InputBuffer->MaxRetDataLength,
|
|
NULL, // FileId
|
|
InputBuffer->Timeout,
|
|
(USHORT)(InputBuffer->ResponseExpected ? 0
|
|
: SMB_TRANSACTION_NO_RESPONSE),
|
|
0,NULL, NULL); // NtTransaction
|
|
|
|
RdrDereferenceDiscardableCode(RdrFileDiscardableSection);
|
|
|
|
*InputBufferLength = sizeof(LMR_TRANSACTION) + InputBuffer->SetupWords;
|
|
|
|
try_return(Status);
|
|
|
|
try_exit:NOTHING;
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
Status = GetExceptionCode();
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
DBGSTATIC
|
|
NTSTATUS
|
|
EnumPrintQueue (
|
|
IN BOOLEAN Wait,
|
|
IN BOOLEAN InFsd,
|
|
IN PIRP Irp,
|
|
IN PICB Icb,
|
|
IN PLMR_REQUEST_PACKET InputBuffer,
|
|
IN OUT PULONG InputBufferLength,
|
|
IN ULONG OutputBufferLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine enumerates the print jobs on an MSNET server.
|
|
|
|
Arguments:
|
|
|
|
IN BOOLEAN Wait, - True IFF redirector can block callers thread on request
|
|
IN PFS_DEVICE_OBJECT DeviceObject, - Device object of destination of Irp
|
|
IN PIRP Irp, - Io Request Packet for request
|
|
IN PIO_STACK_LOCATION IrpSp - Current I/O Stack location for request
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
PLMR_GET_PRINT_QUEUE OutputBuffer;
|
|
|
|
PAGED_CODE();
|
|
|
|
UNREFERENCED_PARAMETER(InFsd);
|
|
|
|
dprintf(DPRT_FSCTL, ("NtFsControlFile: EnumeratePrintQueue\n"));
|
|
|
|
try {
|
|
|
|
if (!NT_SUCCESS(Status = RdrIsOperationValid(Icb, IRP_MJ_FILE_SYSTEM_CONTROL, IoGetCurrentIrpStackLocation(Irp)->FileObject))) {
|
|
try_return(Status);
|
|
}
|
|
|
|
if (Icb->Type != PrinterFile &&
|
|
Icb->Type != ServerRoot) {
|
|
try_return(Status = STATUS_INVALID_DEVICE_REQUEST);
|
|
}
|
|
|
|
if (RdrData.Initialized != RdrStarted) {
|
|
dprintf(DPRT_FSCTL, ("Redirector not started.\n"));
|
|
try_return(Status = STATUS_REDIRECTOR_NOT_STARTED);
|
|
}
|
|
|
|
//
|
|
// Load a pointer to the users input buffer into InputBuffer.
|
|
//
|
|
|
|
OutputBuffer = (PLMR_GET_PRINT_QUEUE)InputBuffer;
|
|
|
|
if (*InputBufferLength < sizeof(LMR_REQUEST_PACKET) ||
|
|
OutputBufferLength < sizeof(LMR_GET_PRINT_QUEUE) + UNLEN ) {
|
|
try_return(Status = STATUS_BUFFER_TOO_SMALL);
|
|
}
|
|
|
|
if (!Wait) {
|
|
try_return(Status = STATUS_PENDING);
|
|
}
|
|
|
|
Status = RdrEnumPrintFile ( Icb, Irp,
|
|
InputBuffer->Parameters.GetPrintQueue.Index,
|
|
OutputBuffer);
|
|
|
|
*InputBufferLength = sizeof(LMR_GET_PRINT_QUEUE) + UNLEN;
|
|
|
|
try_return(Status);
|
|
|
|
try_exit:NOTHING;
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
Status = GetExceptionCode();
|
|
}
|
|
|
|
dprintf(DPRT_FSCTL, ("NtFsControlFile: EnumeratePrintQueue Status %X\n", Status));
|
|
|
|
return Status;
|
|
}
|
|
|
|
DBGSTATIC
|
|
NTSTATUS
|
|
GetPrintJobId (
|
|
IN BOOLEAN Wait,
|
|
IN BOOLEAN InFsd,
|
|
IN PIRP Irp,
|
|
IN PICB Icb,
|
|
IN PLMR_REQUEST_PACKET InputBuffer,
|
|
IN OUT PULONG InputBufferLength,
|
|
OUT PVOID OutputBuffer,
|
|
IN ULONG OutputBufferLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine enumerates the print jobs on an MSNET server.
|
|
|
|
Arguments:
|
|
|
|
IN BOOLEAN Wait, - True IFF redirector can block callers thread on request
|
|
IN PFS_DEVICE_OBJECT DeviceObject, - Device object of destination of Irp
|
|
IN PIRP Irp, - Io Request Packet for request
|
|
IN PIO_STACK_LOCATION IrpSp - Current I/O Stack location for request
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
PAGED_CODE();
|
|
|
|
UNREFERENCED_PARAMETER(InFsd);
|
|
|
|
dprintf(DPRT_FSCTL, ("NtFsControlFile: EnumeratePrintQueue\n"));
|
|
|
|
try {
|
|
|
|
if (!NT_SUCCESS(Status = RdrIsOperationValid(Icb, IRP_MJ_FILE_SYSTEM_CONTROL, IoGetCurrentIrpStackLocation(Irp)->FileObject))) {
|
|
try_return(Status);
|
|
}
|
|
|
|
if (Icb->Type != PrinterFile &&
|
|
Icb->Type != ServerRoot) {
|
|
try_return(Status = STATUS_INVALID_DEVICE_REQUEST);
|
|
}
|
|
|
|
if (RdrData.Initialized != RdrStarted) {
|
|
dprintf(DPRT_FSCTL, ("Redirector not started.\n"));
|
|
try_return(Status = STATUS_REDIRECTOR_NOT_STARTED);
|
|
}
|
|
|
|
//
|
|
// Load a pointer to the users input buffer into InputBuffer.
|
|
//
|
|
|
|
if (OutputBufferLength < sizeof(QUERY_PRINT_JOB_INFO) ) {
|
|
try_return(Status = STATUS_BUFFER_TOO_SMALL);
|
|
}
|
|
|
|
if (!Wait) {
|
|
try_return(Status = STATUS_PENDING);
|
|
}
|
|
|
|
Status = RdrGetPrintJobId ( Icb, Irp, OutputBuffer);
|
|
|
|
*InputBufferLength = sizeof(QUERY_PRINT_JOB_INFO);
|
|
|
|
try_return(Status);
|
|
|
|
try_exit:NOTHING;
|
|
} except (RdrExceptionFilter(GetExceptionInformation(), &Status)) {
|
|
Status = RdrProcessException( Irp, Status );
|
|
}
|
|
|
|
dprintf(DPRT_FSCTL, ("NtFsControlFile: EnumeratePrintQueue Status %X\n", Status));
|
|
|
|
return Status;
|
|
}
|
|
DBGSTATIC
|
|
NTSTATUS
|
|
DeleteConnection (
|
|
IN BOOLEAN Wait,
|
|
IN BOOLEAN InFsd,
|
|
IN PIRP Irp OPTIONAL,
|
|
IN PICB Icb,
|
|
IN PLMR_REQUEST_PACKET InputBuffer,
|
|
IN ULONG InputBufferLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sets the username for the NT redirector.
|
|
|
|
Arguments:
|
|
|
|
IN BOOLEAN Wait, - True IFF redirector can block callers thread on request
|
|
IN PFS_DEVICE_OBJECT DeviceObject, - Device object of destination of Irp
|
|
IN PIRP Irp, - Io Request Packet for request
|
|
IN PIO_STACK_LOCATION IrpSp - Current I/O Stack location for request
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
PFCB TreeConnectFcb;
|
|
ULONG Level;
|
|
|
|
PAGED_CODE();
|
|
|
|
UNREFERENCED_PARAMETER(Wait);
|
|
UNREFERENCED_PARAMETER(InFsd);
|
|
|
|
dprintf(DPRT_FSCTL, ("NtFsControlFile: DeleteConnection "));
|
|
|
|
if (RdrData.Initialized != RdrStarted) {
|
|
dprintf(DPRT_FSCTL, ("Redirector not started.\n"));
|
|
return Status = STATUS_REDIRECTOR_NOT_STARTED;
|
|
}
|
|
|
|
TreeConnectFcb = Icb->Fcb;
|
|
|
|
if ((Icb->Flags & ICB_TCONCREATED) == 0) {
|
|
return Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
}
|
|
|
|
//
|
|
// Load a pointer to the users input buffer into InputBuffer
|
|
//
|
|
|
|
try {
|
|
if (InputBufferLength != sizeof(LMR_REQUEST_PACKET)) {
|
|
return Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
if (InputBuffer->Version != REQUEST_PACKET_VERSION) {
|
|
return Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
Level = InputBuffer->Level;
|
|
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
return (Status = GetExceptionCode());
|
|
}
|
|
|
|
if (Level > USE_LOTS_OF_FORCE) {
|
|
return Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
|
|
Status = RdrDeleteConnection(Irp, TreeConnectFcb->Connection, &Icb->DeviceName,
|
|
Icb->Se, Level);
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
RdrConvertType3FsControlToType2FsControl (
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine does the work necessary to convert a type 3 FsCtl to a
|
|
type 2 FsCtl. We do this when we have to pass a user IRP to the FSP.
|
|
|
|
|
|
Arguments:
|
|
|
|
IN PIRP Irp - Supplies an IRP to convert
|
|
IN PIO_STACK_LOCATION IrpSp - Supplies an Irp Stack location for convenience
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Status of operation
|
|
|
|
Note: This must be called in the FSD.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Lock the unbuffered part of the users request buffer, we
|
|
// are passing the request to the FSP.
|
|
//
|
|
|
|
if (IrpSp->Parameters.FileSystemControl.OutputBufferLength != 0) {
|
|
Status = RdrLockUsersBuffer(Irp, IoWriteAccess, IrpSp->Parameters.FileSystemControl.OutputBufferLength);
|
|
|
|
//
|
|
// If we were unable to lock the users output buffer, return now.
|
|
//
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
}
|
|
|
|
ASSERT (Irp->AssociatedIrp.SystemBuffer == NULL);
|
|
|
|
try {
|
|
if (IrpSp->Parameters.FileSystemControl.InputBufferLength != 0) {
|
|
Irp->AssociatedIrp.SystemBuffer = ExAllocatePoolWithQuota (PagedPool,
|
|
IrpSp->Parameters.FileSystemControl.InputBufferLength);
|
|
|
|
|
|
if (Irp->AssociatedIrp.SystemBuffer == NULL) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlCopyMemory( Irp->AssociatedIrp.SystemBuffer,
|
|
IrpSp->Parameters.FileSystemControl.Type3InputBuffer,
|
|
IrpSp->Parameters.FileSystemControl.InputBufferLength);
|
|
|
|
Irp->Flags |= (IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER);
|
|
|
|
} else {
|
|
Irp->AssociatedIrp.SystemBuffer = NULL;
|
|
}
|
|
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
return GetExceptionCode();
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN
|
|
PackConnectEntry (
|
|
IN ULONG Level,
|
|
IN OUT PCHAR *BufferStart,
|
|
IN OUT PCHAR *BufferEnd,
|
|
IN ULONG BufferDisplacment,
|
|
IN PUNICODE_STRING DeviceName,
|
|
IN PCONNECTLISTENTRY Cle,
|
|
IN PSECURITY_ENTRY Se,
|
|
OUT PULONG TotalBytesNeeded
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine packs a connectlistentry into the buffer provided updating
|
|
all relevant pointers.
|
|
|
|
|
|
Arguments:
|
|
|
|
IN ULONG Level - Level of information requested.
|
|
|
|
IN OUT PCHAR *BufferStart - Supplies the output buffer.
|
|
Updated to point to the next buffer
|
|
IN OUT PCHAR *BufferEnd - Supplies the end of the buffer. Updated to
|
|
point before the start of the
|
|
strings being packed.
|
|
IN PVOID UsersBufferStart - Supplies the start of the buffer in the users
|
|
address space
|
|
IN PCONNECTLISTENTRY Cle - Supplies the CLE to enumerate.
|
|
IN OUT PULONG TotalBytesNeeded - Updated to account for the length of this
|
|
entry
|
|
|
|
Return Value:
|
|
|
|
BOOLEAN - True if the entry was successfully packed into the buffer.
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
PWCHAR ConnectName; // Buffer to hold the packed name
|
|
ULONG NameLength;
|
|
ULONG BufferSize;
|
|
PLMR_CONNECTION_INFO_3 ConnectionInfo = (PLMR_CONNECTION_INFO_3)*BufferStart;
|
|
|
|
PAGED_CODE();
|
|
|
|
switch (Level) {
|
|
case 0:
|
|
BufferSize = sizeof(LMR_CONNECTION_INFO_0);
|
|
break;
|
|
case 1:
|
|
BufferSize = sizeof(LMR_CONNECTION_INFO_1);
|
|
break;
|
|
case 2:
|
|
BufferSize = sizeof(LMR_CONNECTION_INFO_2);
|
|
break;
|
|
case 3:
|
|
BufferSize = sizeof(LMR_CONNECTION_INFO_3);
|
|
break;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
ConnectName = ALLOCATE_POOL(NonPagedPool, MAX_PATH * sizeof( *ConnectName ), POOL_COMPUTERNAME);
|
|
|
|
if( ConnectName == NULL ) {
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
*BufferStart = ((PUCHAR)*BufferStart) + BufferSize;
|
|
|
|
//
|
|
// Initialize the name to "\\"
|
|
//
|
|
|
|
ConnectName[0] = L'\\';
|
|
ConnectName[1] = L'\\';
|
|
|
|
//
|
|
// Concatenate the server name.
|
|
//
|
|
|
|
RtlCopyMemory(&ConnectName[2], Cle->Server->Text.Buffer, Cle->Server->Text.Length);
|
|
|
|
//
|
|
// Stick a "\" between the server name and the share name.
|
|
//
|
|
|
|
ConnectName[2+(Cle->Server->Text.Length / sizeof(WCHAR))] = L'\\';
|
|
|
|
//
|
|
// Append the share name to the server name.
|
|
//
|
|
|
|
RtlCopyMemory(&ConnectName[2+(Cle->Server->Text.Length / sizeof(WCHAR))+1], Cle->Text.Buffer, Cle->Text.Length);
|
|
|
|
//
|
|
// Compute the length of the name.
|
|
//
|
|
|
|
NameLength = (2*sizeof(WCHAR))+Cle->Text.Length+(1*sizeof(WCHAR))+Cle->Server->Text.Length;
|
|
|
|
//
|
|
// Update the total number of bytes needed for this structure.
|
|
//
|
|
|
|
*TotalBytesNeeded += NameLength + BufferSize;
|
|
|
|
if (*BufferStart > *BufferEnd) {
|
|
FREE_POOL( ConnectName );
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Initialize the STRING in buffer
|
|
//
|
|
ConnectionInfo->UNCName.Length = (USHORT)NameLength;
|
|
ConnectionInfo->UNCName.MaximumLength = (USHORT)NameLength;
|
|
ConnectionInfo->UNCName.Buffer = ConnectName;
|
|
|
|
ConnectionInfo->ResumeKey = Cle->SerialNumber;
|
|
|
|
if (Level > 0) {
|
|
ULONG NumberOfDirectories;
|
|
ULONG NumberOfTreeConnections;
|
|
ULONG ConnectionStatus = 0;
|
|
|
|
switch (Cle->Type) {
|
|
case CONNECT_DISK:
|
|
ConnectionInfo->SharedResourceType = FILE_DEVICE_DISK;
|
|
break;
|
|
case CONNECT_PRINT:
|
|
ConnectionInfo->SharedResourceType = FILE_DEVICE_PRINTER;
|
|
break;
|
|
case CONNECT_COMM:
|
|
ConnectionInfo->SharedResourceType = FILE_DEVICE_SERIAL_PORT;
|
|
break;
|
|
case CONNECT_IPC:
|
|
ConnectionInfo->SharedResourceType = FILE_DEVICE_NAMED_PIPE;
|
|
break;
|
|
default:
|
|
ConnectionInfo->SharedResourceType = FILE_DEVICE_UNKNOWN;
|
|
}
|
|
|
|
|
|
if ( !(Cle->HasTreeId) ) {
|
|
|
|
ConnectionStatus = USE_DISCONN;
|
|
|
|
} else {
|
|
|
|
if (!ExAcquireResourceExclusive(&Cle->Server->SessionStateModifiedLock, FALSE)) {
|
|
|
|
//
|
|
// If the initialization event is in the not-signalled state,
|
|
// then this use is being reconnected.
|
|
//
|
|
|
|
if (Cle->Type == CONNECT_WILD) {
|
|
ConnectionStatus = USE_CONN;
|
|
|
|
} else {
|
|
|
|
ConnectionStatus = USE_RECONN;
|
|
}
|
|
} else {
|
|
ExReleaseResource(&Cle->Server->SessionStateModifiedLock);
|
|
|
|
ConnectionStatus = USE_OK;
|
|
}
|
|
}
|
|
|
|
ConnectionInfo->ConnectionStatus = ConnectionStatus;
|
|
|
|
RdrGetConnectionReferences(Cle, DeviceName, Se,
|
|
&NumberOfTreeConnections,
|
|
&NumberOfDirectories,
|
|
&ConnectionInfo->NumberFilesOpen
|
|
);
|
|
|
|
}
|
|
|
|
if (Level > 1) {
|
|
|
|
ConnectionInfo->Capabilities = 0;
|
|
|
|
if (Cle->Server->Capabilities & DF_UNICODE) {
|
|
ConnectionInfo->Capabilities |= CAPABILITY_UNICODE;
|
|
}
|
|
|
|
if (Cle->Server->Capabilities & DF_RPC_REMOTE) {
|
|
ConnectionInfo->Capabilities |= CAPABILITY_RPC;
|
|
}
|
|
|
|
if ((Cle->Server->Capabilities & DF_NT_SMBS) &&
|
|
(Cle->Server->Capabilities & DF_RPC_REMOTE)) {
|
|
ConnectionInfo->Capabilities |= CAPABILITY_SAM_PROTOCOL;
|
|
}
|
|
|
|
if (Cle->Server->Capabilities & DF_MIXEDCASE) {
|
|
ConnectionInfo->Capabilities |= CAPABILITY_CASE_SENSITIVE_PASSWDS;
|
|
}
|
|
|
|
if (Cle->Server->Capabilities & DF_LANMAN10) {
|
|
ConnectionInfo->Capabilities |= CAPABILITY_REMOTE_ADMIN_PROTOCOL;
|
|
}
|
|
|
|
}
|
|
|
|
if (!RdrPackNtString(&ConnectionInfo->UNCName, BufferDisplacment, *BufferStart, BufferEnd)) {
|
|
if (Level > 1) {
|
|
ConnectionInfo->UserName.Length = 0;
|
|
}
|
|
FREE_POOL( ConnectName );
|
|
return FALSE;
|
|
}
|
|
|
|
if (Level > 1) {
|
|
//
|
|
// Get the user name
|
|
//
|
|
WCHAR UserName[UNLEN+1];
|
|
PWSTR UserPointer = UserName;
|
|
UNICODE_STRING DomainName;
|
|
NTSTATUS Status;
|
|
|
|
RtlInitUnicodeString(
|
|
&DomainName,
|
|
NULL
|
|
);
|
|
|
|
Status = RdrCopyUnicodeUserName(&UserPointer, Se);
|
|
|
|
//
|
|
// Null terminate the user name for RtlInitUnicodeString. If this
|
|
// is a null session, this will set the username to a null string.
|
|
//
|
|
|
|
*UserPointer = UNICODE_NULL;
|
|
|
|
RtlInitUnicodeString(&ConnectionInfo->UserName, UserName);
|
|
|
|
if (!RdrPackNtString(&ConnectionInfo->UserName, BufferDisplacment, *BufferStart, BufferEnd)) {
|
|
FREE_POOL( ConnectName );
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Get the domain name. If there is no associated domain name, set
|
|
// the information to a null string. We need to pass a stack
|
|
// address because RdrGetUnicodeDomainName does a KeAttachProcess.
|
|
//
|
|
|
|
RdrGetUnicodeDomainName( &DomainName, Se );
|
|
|
|
ConnectionInfo->DomainName = DomainName;
|
|
if( DomainName.Length != 0 ) {
|
|
|
|
PUSHORT p = ConnectionInfo->DomainName.Buffer;
|
|
|
|
*TotalBytesNeeded += ConnectionInfo->DomainName.Length;
|
|
|
|
if( !RdrPackNtString( &ConnectionInfo->DomainName, BufferDisplacment, *BufferStart, BufferEnd) ) {
|
|
FREE_POOL( ConnectName );
|
|
FREE_POOL( p );
|
|
return FALSE;
|
|
}
|
|
|
|
FREE_POOL( p );
|
|
}
|
|
}
|
|
|
|
if (Level > 2) {
|
|
ConnectionInfo->Throughput = Cle->Server->Throughput;
|
|
ConnectionInfo->Delay = Cle->Server->Delay;
|
|
ConnectionInfo->IsSpecialIpcConnection = (Cle->Server->SpecificTransportProvider != NULL);
|
|
ConnectionInfo->Reliable = Cle->Server->Reliable;
|
|
ConnectionInfo->ReadAhead = Cle->Server->ReadAhead;
|
|
ConnectionInfo->TimeZoneBias = Cle->Server->TimeZoneBias;
|
|
ConnectionInfo->Core = (Cle->Server->Capabilities & DF_CORE) != 0;
|
|
ConnectionInfo->MsNet103 = (Cle->Server->Capabilities & DF_OLDRAWIO) != 0;
|
|
ConnectionInfo->Lanman10 = (Cle->Server->Capabilities & DF_LANMAN10) != 0;
|
|
ConnectionInfo->WindowsForWorkgroups = (Cle->Server->Capabilities & DF_WFW) != 0;
|
|
ConnectionInfo->Lanman20 = (Cle->Server->Capabilities & DF_LANMAN20) != 0;
|
|
ConnectionInfo->Lanman21 = (Cle->Server->Capabilities & DF_LANMAN21) != 0;
|
|
ConnectionInfo->WindowsNt = (Cle->Server->Capabilities & DF_NTPROTOCOL) != 0;
|
|
ConnectionInfo->MixedCasePasswords = (Cle->Server->Capabilities & DF_MIXEDCASEPW) != 0;
|
|
ConnectionInfo->MixedCaseFiles = (Cle->Server->Capabilities & DF_MIXEDCASE) != 0;
|
|
ConnectionInfo->LongNames = (Cle->Server->Capabilities & DF_LONGNAME) != 0;
|
|
ConnectionInfo->ExtendedNegotiateResponse = (Cle->Server->Capabilities & DF_EXTENDNEGOT) != 0;
|
|
ConnectionInfo->LockAndRead = (Cle->Server->Capabilities & DF_LOCKREAD) != 0;
|
|
ConnectionInfo->NtSecurity = (Cle->Server->Capabilities & DF_SECURITY) != 0;
|
|
ConnectionInfo->SupportsEa = (Cle->Server->Capabilities & DF_SUPPORTEA) != 0;
|
|
ConnectionInfo->NtNegotiateResponse = (Cle->Server->Capabilities & DF_NTNEGOTIATE) != 0;
|
|
ConnectionInfo->CancelSupport = (Cle->Server->Capabilities & DF_CANCEL) != 0;
|
|
ConnectionInfo->UnicodeStrings = (Cle->Server->Capabilities & DF_UNICODE) != 0;
|
|
ConnectionInfo->LargeFiles = (Cle->Server->Capabilities & DF_LARGE_FILES) != 0;
|
|
ConnectionInfo->NtSmbs = (Cle->Server->Capabilities & DF_NT_SMBS) != 0;
|
|
ConnectionInfo->RpcRemoteAdmin = (Cle->Server->Capabilities & DF_RPC_REMOTE) != 0;
|
|
ConnectionInfo->NtStatusCodes = (Cle->Server->Capabilities & DF_NT_STATUS) != 0;
|
|
ConnectionInfo->LevelIIOplock = (Cle->Server->Capabilities & DF_OPLOCK_LVL2) != 0;
|
|
ConnectionInfo->UtcTime = (Cle->Server->Capabilities & DF_TIME_IS_UTC) != 0;
|
|
ConnectionInfo->UserSecurity = Cle->Server->UserSecurity;
|
|
ConnectionInfo->EncryptsPasswords = Cle->Server->EncryptPasswords;
|
|
|
|
if (NT_SUCCESS(RdrReferenceTransportConnection(Cle->Server))) {
|
|
ConnectionInfo->TransportName = Cle->Server->ConnectionContext->TransportProvider->PagedTransport->TransportName;
|
|
|
|
if (!RdrPackNtString(&ConnectionInfo->TransportName, BufferDisplacment, *BufferStart, BufferEnd)) {
|
|
RdrDereferenceTransportConnection(Cle->Server);
|
|
FREE_POOL( ConnectName );
|
|
return FALSE;
|
|
}
|
|
|
|
RdrDereferenceTransportConnection(Cle->Server);
|
|
} else {
|
|
ConnectionInfo->TransportName.Buffer = NULL;
|
|
ConnectionInfo->TransportName.Length = 0;
|
|
ConnectionInfo->TransportName.MaximumLength = 0;
|
|
}
|
|
|
|
}
|
|
|
|
FREE_POOL( ConnectName );
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
DBGSTATIC
|
|
NTSTATUS
|
|
StopRedirector (
|
|
IN BOOLEAN Wait,
|
|
IN BOOLEAN InFsd,
|
|
IN PFS_DEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sets the username for the NT redirector.
|
|
|
|
Arguments:
|
|
|
|
IN BOOLEAN Wait, - True IFF redirector can block callers thread on request
|
|
IN BOOLEAN InFsd,
|
|
IN PFS_DEVICE_OBJECT DeviceObject, - Device object of destination of Irp
|
|
IN PIRP Irp, - Io Request Packet for request
|
|
IN PIO_STACK_LOCATION IrpSp - Current I/O Stack location for request
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
PICB Icb;
|
|
PFCB Fcb;
|
|
|
|
PAGED_CODE();
|
|
|
|
Wait;DeviceObject;IrpSp;Irp;
|
|
|
|
if (RdrData.Initialized != RdrStarted) {
|
|
dprintf(DPRT_FSCTL, ("Redirector not started\n"));
|
|
return (Status = STATUS_REDIRECTOR_NOT_STARTED);
|
|
}
|
|
|
|
//
|
|
// The stop redirector code has to be executed in the FSP because of
|
|
// the handle (MupHandle) is only valid in the FSP.
|
|
//
|
|
|
|
if (InFsd) {
|
|
return (Status = STATUS_PENDING);
|
|
}
|
|
|
|
//
|
|
// Prevent any creates from now on.
|
|
//
|
|
|
|
RdrData.Initialized = RdrStopping;
|
|
|
|
//
|
|
// attempt to shut down SmbTrace, we ignore the status code, since
|
|
// it merely indicates whether SmbTrace was running or not.
|
|
//
|
|
|
|
if (SmbTraceStop != NULL) {
|
|
SmbTraceStop(NULL, SMBTRACE_REDIRECTOR);
|
|
}
|
|
|
|
//
|
|
// First shut down all access to the network. This means unbinding
|
|
// ourselves from ALL of our bound transports.
|
|
//
|
|
|
|
#ifdef RDR_PNP_POWER
|
|
Status = RdrDeRegisterForPnpNotifications();
|
|
|
|
if( !NT_SUCCESS( Status ) ) {
|
|
return Status;
|
|
}
|
|
#endif
|
|
|
|
Status = RdrUnbindFromAllTransports(Irp);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
IoStopTimer((PDEVICE_OBJECT )DeviceObject);
|
|
|
|
SeUnregisterLogonSessionTerminatedRoutine(
|
|
(PSE_LOGON_SESSION_TERMINATED_ROUTINE)
|
|
RdrHandleLogonSessionTermination);
|
|
|
|
//
|
|
// Next unregister the redirector with the multiple UNC provider.
|
|
//
|
|
|
|
FsRtlDeregisterUncProvider( RdrMupHandle );
|
|
|
|
RdrMupHandle = (HANDLE)-1;
|
|
|
|
//
|
|
// Now clean up the redirector data structures that were created when.
|
|
// the redirector was started.
|
|
//
|
|
|
|
//
|
|
// Now get rid of the structures associated with exchanging SMBs.
|
|
//
|
|
|
|
RdrpUninitializeSmbExchange();
|
|
|
|
//
|
|
// And clean up our security stuff.
|
|
//
|
|
|
|
if (!NT_SUCCESS(Status = RdrpUninitializeSecurity())) {
|
|
return(Status);
|
|
}
|
|
|
|
//
|
|
// Free up the memory used to hold the computer name.
|
|
//
|
|
|
|
FREE_POOL(RdrData.ComputerName);
|
|
|
|
//
|
|
// Free up the memory used to hold the domain name.
|
|
//
|
|
|
|
FREE_POOL(RdrPrimaryDomain.Buffer);
|
|
|
|
RdrData.Initialized = RdrStopped;
|
|
|
|
#ifdef RASAUTODIAL
|
|
//
|
|
// Unbind with the automatic connection driver.
|
|
//
|
|
RdrAcdUnbind();
|
|
#endif // RASAUTODIAL
|
|
|
|
//
|
|
// If there is one Fcb and one Icb then tell the caller that the
|
|
// redirector can be unloaded. This is because the only handle is
|
|
// the handle used to stop the redirector.
|
|
//
|
|
|
|
// Lock the FCB database.
|
|
if (!NT_SUCCESS(KeWaitForMutexObject(&RdrDatabaseMutex,
|
|
Executive, KernelMode, FALSE, NULL))) {
|
|
InternalError(("Unable to claim FCB mutex in RdrAllocateFCB"));
|
|
return Status;
|
|
}
|
|
|
|
Fcb = CONTAINING_RECORD(RdrFcbHead.Flink, FCB, GlobalNext);
|
|
|
|
Icb = CONTAINING_RECORD(Fcb->InstanceChain.Flink, ICB, InstanceNext);
|
|
|
|
if (( RdrFcbHead.Flink->Flink != &RdrFcbHead ) ||
|
|
( Icb->InstanceNext.Flink != &Fcb->InstanceChain )) {
|
|
Status = STATUS_REDIRECTOR_HAS_OPEN_HANDLES;
|
|
}
|
|
|
|
KeReleaseMutex(&RdrDatabaseMutex, FALSE);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
DBGSTATIC
|
|
NTSTATUS
|
|
GetHintSize (
|
|
IN BOOLEAN Wait,
|
|
IN PFS_DEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sets the username for the NT redirector.
|
|
|
|
Arguments:
|
|
|
|
IN BOOLEAN Wait, - True IFF redirector can block callers thread on request
|
|
IN PFS_DEVICE_OBJECT DeviceObject, - Device object of destination of Irp
|
|
IN PIRP Irp, - Io Request Packet for request
|
|
IN PIO_STACK_LOCATION IrpSp - Current I/O Stack location for request
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
|
|
|
|
PAGED_CODE();
|
|
|
|
Wait;DeviceObject;IrpSp;Irp;
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
RdrFsdDeviceIoControlFile (
|
|
IN PFS_DEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is the redir device io control IRP handler.
|
|
|
|
Arguments:
|
|
|
|
IN PDEVICE_OBJECT DeviceObject - Supplies a device object for the request.
|
|
IN PIRP Irp - Supplies an IRP for the create request.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Final Status of operation
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
PAGED_CODE();
|
|
|
|
if (DeviceObject == (PFS_DEVICE_OBJECT)BowserDeviceObject) {
|
|
return BowserFsdDeviceIoControlFile(BowserDeviceObject, Irp);
|
|
}
|
|
|
|
FsRtlEnterFileSystem();
|
|
|
|
Status = RdrFscDeviceIoControlFile(TRUE, IoIsOperationSynchronous(Irp),
|
|
DeviceObject,
|
|
Irp);
|
|
FsRtlExitFileSystem();
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
RdrFspDeviceIoControlFile (
|
|
IN PFS_DEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is the redir device io control IRP handler.
|
|
|
|
Arguments:
|
|
|
|
IN PDEVICE_OBJECT DeviceObject - Supplies a device object for the request.
|
|
IN PIRP Irp - Supplies an IRP for the create request.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Final Status of operation
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
PAGED_CODE();
|
|
|
|
Status = RdrFscDeviceIoControlFile(FALSE, TRUE,
|
|
DeviceObject,
|
|
Irp);
|
|
return Status;
|
|
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
RdrFscDeviceIoControlFile (
|
|
IN BOOLEAN InFsd,
|
|
IN BOOLEAN Wait,
|
|
IN PFS_DEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is the redir device io control IRP handler.
|
|
|
|
Arguments:
|
|
|
|
IN BOOLEAN InFsd - True if the request is from the FSD, false if from FSP.
|
|
IN BOOLEAN Wait - True if the Rdr can tie up the users thread for this
|
|
request.
|
|
IN PDEVICE_OBJECT DeviceObject - Supplies a device object for the request.
|
|
IN PIRP Irp - Supplies an IRP for the create request.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Final Status of operation
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
PVOID InputBuffer;
|
|
ULONG InputBufferLength;
|
|
PVOID OutputBuffer;
|
|
ULONG OutputBufferLength;
|
|
ULONG IoControlCode = IrpSp->Parameters.DeviceIoControl.IoControlCode;
|
|
|
|
PAGED_CODE();
|
|
|
|
try {
|
|
|
|
//
|
|
// Before we call the worker functions, prep the parameters to those
|
|
// functions.
|
|
//
|
|
|
|
//
|
|
// The lengths of the various buffers are easy to find, they're in the
|
|
// Irp stack location.
|
|
//
|
|
|
|
OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
|
|
|
|
InputBufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
|
|
|
|
//
|
|
// The input buffer is either in Irp->AssociatedIrp.SystemBuffer, or
|
|
// in the Type3InputBuffer for type 3 IRP's.
|
|
//
|
|
|
|
InputBuffer = Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
//
|
|
// If we are in the FSD, then the input buffer is in Type3InputBuffer
|
|
// on type 3 api's, not in SystemBuffer.
|
|
//
|
|
|
|
if (InputBuffer == NULL) {
|
|
|
|
//
|
|
// This had better be a type 3 IOCTL, or the input buffer had
|
|
// better be 0 length.
|
|
//
|
|
|
|
ASSERT (((IoControlCode & 3) == METHOD_NEITHER) || (IrpSp->Parameters.FileSystemControl.InputBufferLength == 0));
|
|
|
|
if ((IrpSp->Parameters.DeviceIoControl.InputBufferLength != 0) &&
|
|
((IoControlCode & 3) == METHOD_NEITHER)) {
|
|
|
|
//
|
|
// And we had better be in the FSD.
|
|
//
|
|
|
|
ASSERT (InFsd);
|
|
|
|
InputBuffer = IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
|
|
}
|
|
}
|
|
|
|
OutputBuffer = InputBuffer;
|
|
|
|
if ( IoControlCode != IOCTL_REDIR_QUERY_PATH ) {
|
|
Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
} else {
|
|
|
|
PQUERY_PATH_REQUEST qpRequest;
|
|
PQUERY_PATH_RESPONSE qpResponse;
|
|
UNICODE_STRING FilePathName;
|
|
UNICODE_STRING PathName;
|
|
PCONNECTLISTENTRY Connection;
|
|
PSECURITY_ENTRY Se;
|
|
BOOLEAN OpeningMailslotFile;
|
|
ULONG ConnectDisposition = FILE_OPEN_IF;
|
|
ULONG ConnectionType;
|
|
BOOLEAN bConn;
|
|
|
|
qpRequest = InputBuffer;
|
|
|
|
FilePathName.Buffer = qpRequest->FilePathName;
|
|
FilePathName.Length = (USHORT)qpRequest->PathNameLength;
|
|
|
|
Status = RdrDetermineFileConnection(Irp,
|
|
&FilePathName,
|
|
qpRequest->SecurityContext,
|
|
&PathName,
|
|
&Connection,
|
|
&Se,
|
|
NULL,
|
|
0,
|
|
FALSE,
|
|
&OpeningMailslotFile,
|
|
&ConnectDisposition,
|
|
&ConnectionType,
|
|
NULL,
|
|
&bConn);
|
|
|
|
if ( NT_SUCCESS(Status) ) {
|
|
qpResponse = OutputBuffer;
|
|
qpResponse->LengthAccepted = Connection->Text.Length +
|
|
Connection->Server->Text.Length + 2*sizeof(WCHAR);
|
|
|
|
Status = RdrReconnectConnection(Irp, Connection, Se);
|
|
|
|
//
|
|
// Dereference the connection, we're done with it now.
|
|
//
|
|
|
|
RdrDereferenceConnection(Irp, Connection, Se, FALSE);
|
|
|
|
//
|
|
// And dereference the security entry, we're done with it too.
|
|
//
|
|
|
|
RdrDereferenceSecurityEntry(Se->NonPagedSecurityEntry);
|
|
}
|
|
}
|
|
|
|
dprintf(DPRT_FSCTL, ("Returning status: %X\n", Status));
|
|
|
|
#if DBG
|
|
} except (RdrExceptionFilter(GetExceptionInformation(), &Status)) {
|
|
|
|
Status = RdrProcessException( Irp, Status);
|
|
|
|
}
|
|
|
|
|
|
#else
|
|
} except ( EXCEPTION_EXECUTE_HANDLER ) {
|
|
|
|
Status = GetExceptionCode();
|
|
}
|
|
#endif
|
|
|
|
if (Status != STATUS_PENDING) {
|
|
RdrCompleteRequest(Irp, Status);
|
|
}
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
DBGSTATIC
|
|
NTSTATUS
|
|
GetStatistics (
|
|
IN BOOLEAN Wait,
|
|
IN BOOLEAN InFsd,
|
|
IN PIRP Irp,
|
|
IN PICB Icb,
|
|
IN PLMR_REQUEST_PACKET InputBuffer,
|
|
IN OUT PULONG InputBufferLength,
|
|
IN ULONG OutputBufferLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine reads all the statistics counts for the application. The buffer size
|
|
must be exactly correct for the data. This helps ensure that the data will be
|
|
interpreted correctly.
|
|
|
|
Arguments:
|
|
|
|
IN BOOLEAN Wait, - True IFF redirector can block callers thread on request
|
|
IN PFS_DEVICE_OBJECT DeviceObject, - Device object of destination of Irp
|
|
IN PIRP Irp, - Io Request Packet for request
|
|
IN PICB Icb,
|
|
IN PLMR_REQUEST_PACKET InputBuffer,
|
|
IN OUT PULONG InputBufferLength,
|
|
IN ULONG OutputBufferLength
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
KIRQL OldIrql;
|
|
|
|
UNREFERENCED_PARAMETER(InFsd);
|
|
|
|
RdrReferenceDiscardableCode(RdrVCDiscardableSection);
|
|
|
|
DISCARDABLE_CODE(RdrVCDiscardableSection);
|
|
|
|
dprintf(DPRT_FSCTL, ("NtFsControlFile: GetStatistics "));
|
|
|
|
|
|
if (Icb->Type != Redirector) {
|
|
Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
goto ReturnStatus;
|
|
}
|
|
|
|
if (RdrData.Initialized != RdrStarted) {
|
|
dprintf(DPRT_FSCTL, ("Redirector not started.\n"));
|
|
Status = STATUS_REDIRECTOR_NOT_STARTED;
|
|
goto ReturnStatus;
|
|
}
|
|
|
|
if (OutputBufferLength < sizeof(REDIR_STATISTICS)) {
|
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|
goto ReturnStatus;
|
|
}
|
|
|
|
if (OutputBufferLength != sizeof(REDIR_STATISTICS)) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto ReturnStatus;
|
|
}
|
|
|
|
ACQUIRE_SPIN_LOCK(&RdrStatisticsSpinLock, &OldIrql);
|
|
|
|
//
|
|
// Note, we do not need to get the spinlock used for CurrentCommands because
|
|
// it is unrelated to any other statistics we return.
|
|
//
|
|
|
|
RtlCopyMemory(InputBuffer, &RdrStatistics, OutputBufferLength);
|
|
RELEASE_SPIN_LOCK(&RdrStatisticsSpinLock, OldIrql);
|
|
Status = STATUS_SUCCESS;
|
|
|
|
ReturnStatus:
|
|
RdrDereferenceDiscardableCode(RdrVCDiscardableSection);
|
|
|
|
if ( Status == STATUS_SUCCESS ) {
|
|
Irp->IoStatus.Information = OutputBufferLength;
|
|
} else {
|
|
Irp->IoStatus.Information = 0;
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
|
|
DBGSTATIC
|
|
NTSTATUS
|
|
StartSmbTrace (
|
|
IN BOOLEAN Wait,
|
|
IN BOOLEAN InFsd,
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp,
|
|
IN PLMR_REQUEST_PACKET InputBuffer,
|
|
IN ULONG InputBufferLength,
|
|
IN ULONG OutputBufferLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine starts SmbTrace support, creating shared memory and
|
|
events and starting the SmbTrace thread.
|
|
|
|
Arguments:
|
|
|
|
IN BOOLEAN Wait - True IFF redirector can block callers thread on request
|
|
IN BOOLEAN InFsd - True if the request is from the FSD, false if from FSP.
|
|
IN PIRP Irp - Io Request Packet for request
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
IN PLMR_REQUEST_PACKET InputBuffer
|
|
IN ULONG InputBufferLength
|
|
IN ULONG OutputBufferLength
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
PIRP QueryIrp = NULL;
|
|
HANDLE SmbTraceHandle = NULL;
|
|
PFILE_OBJECT SmbTraceFileObject = NULL;
|
|
|
|
PAGED_CODE();
|
|
|
|
dprintf(DPRT_FSCTL, ("NtFsControlFile: StartSmbTrace\n"));
|
|
|
|
//
|
|
// do some state checking in Fsd, do everything else in Fsp
|
|
//
|
|
|
|
if (InFsd) {
|
|
|
|
//
|
|
// Redirector must be started
|
|
//
|
|
if (RdrData.Initialized != TRUE) {
|
|
dprintf(DPRT_FSCTL, ("Redirector not started.\n"));
|
|
Status = STATUS_REDIRECTOR_NOT_STARTED;
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// SmbTrace must not already be running
|
|
//
|
|
if ( SmbTraceActive[SMBTRACE_REDIRECTOR] ) {
|
|
Status = STATUS_SHARING_VIOLATION;
|
|
return Status;
|
|
}
|
|
|
|
Status = STATUS_PENDING;
|
|
return Status;
|
|
|
|
}
|
|
|
|
//
|
|
// Initialize SmbTrace. This is a no-op if it's already been done.
|
|
//
|
|
|
|
Status = SmbTraceInitialize(SMBTRACE_REDIRECTOR);
|
|
if ( NT_SUCCESS(Status) ) {
|
|
|
|
//
|
|
// Create shared memory, create events, start SmbTrace thread,
|
|
// and indicate that this is the redirector
|
|
//
|
|
|
|
Status = SmbTraceStart(
|
|
InputBufferLength,
|
|
OutputBufferLength,
|
|
InputBuffer,
|
|
IrpSp->FileObject,
|
|
SMBTRACE_REDIRECTOR
|
|
);
|
|
|
|
if ( NT_SUCCESS(Status) ) {
|
|
|
|
//
|
|
// Record the length of the return information, which is
|
|
// simply the length of the output buffer, validated by
|
|
// SmbTraceStart.
|
|
//
|
|
|
|
Irp->IoStatus.Information = OutputBufferLength;
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
DBGSTATIC
|
|
NTSTATUS
|
|
StopSmbTrace (
|
|
IN BOOLEAN Wait,
|
|
IN BOOLEAN InFsd,
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine stops SmbTrace support, undoing the effects of
|
|
StartSmbTrace.
|
|
|
|
Arguments:
|
|
|
|
IN BOOLEAN Wait - True IFF redirector can block callers thread on request
|
|
IN BOOLEAN InFsd - True if the request is from the FSD, false if from FSP.
|
|
IN PIRP Irp - Io Request Packet for request
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - STATUS_SUCCESS or STATUS_UNSUCCESSFUL
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
PAGED_CODE();
|
|
|
|
dprintf(DPRT_FSCTL, ("NtFsControlFile: StopSmbTrace\n"));
|
|
|
|
Status = SmbTraceStop( NULL, SMBTRACE_REDIRECTOR );
|
|
|
|
KdPrint(( "StopSmbTrace: SmbTraceStop returned %lC\n", Status));
|
|
|
|
return Status;
|
|
|
|
} // StopSmbTrace
|
|
|
|
|
|
|
|
NTSTATUS
|
|
GetDfsReferral(
|
|
IN PIRP Irp,
|
|
IN PICB Icb,
|
|
IN PCHAR InputBuffer,
|
|
IN ULONG InputBufferLength,
|
|
IN PUCHAR OutputBuffer,
|
|
IN ULONG OutputBufferLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sends a trans2 SMB to retrieve a Dfs referral.
|
|
|
|
Arguments:
|
|
|
|
IN PIRP Irp -- Irp to use
|
|
IN PICB Icb -- The Icb to use. Should be an open of IPC$ on some server
|
|
IN PCHAR InputBuffer -- Should be a DFS_GET_REFERRALS_INPUT_ARG
|
|
IN ULONG InputBufferLength -- Length in bytes of InputBuffer
|
|
IN PUCHAR OutputBuffer -- On return, a DFS_GET_REFERRALS_OUTPUT_BUFFER
|
|
IN OUT PULONG OutputBufferLength -- Length in bytes of OutputBuffer
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
USHORT GetReferralSetup = TRANS2_GET_DFS_REFERRAL;
|
|
ULONG OutParameter, OutSetup, OutData;
|
|
|
|
RdrReferenceDiscardableCode(RdrFileDiscardableSection);
|
|
|
|
OutParameter = 0;
|
|
OutSetup = 0;
|
|
OutData = OutputBufferLength;
|
|
|
|
if (!(Icb->Fcb->Connection->Server->Capabilities & DF_DFSAWARE)) {
|
|
|
|
Status = STATUS_DFS_UNAVAILABLE;
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
} else {
|
|
|
|
Status = RdrTransact(
|
|
Irp,
|
|
Icb->Fcb->Connection,
|
|
Icb->Se,
|
|
(PVOID) &GetReferralSetup,
|
|
sizeof(GetReferralSetup),
|
|
&OutSetup,
|
|
NULL,
|
|
InputBuffer,
|
|
InputBufferLength,
|
|
&OutParameter,
|
|
NULL,
|
|
0,
|
|
OutputBuffer,
|
|
&OutData,
|
|
&Icb->FileId,
|
|
0,
|
|
0,
|
|
0,
|
|
NULL,
|
|
NULL);
|
|
|
|
Irp->IoStatus.Information = OutData;
|
|
|
|
}
|
|
|
|
RdrDereferenceDiscardableCode(RdrFileDiscardableSection);
|
|
|
|
return( Status );
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
ReportDfsInconsistency(
|
|
IN PIRP Irp,
|
|
IN PICB Icb,
|
|
IN PCHAR InputBuffer,
|
|
IN ULONG InputBufferLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sends a trans2 SMB to report a Dfs inconsistency.
|
|
|
|
Arguments:
|
|
|
|
IN PIRP Irp -- Irp to use
|
|
IN PICB Icb -- The Icb to use. Should be an open of IPC$ on some server
|
|
IN PCHAR InputBuffer -- Should be a DFS_GET_REFERRALS_INPUT_ARG
|
|
IN ULONG InputBufferLength -- Length in bytes of InputBuffer
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
USHORT GetReferralSetup = TRANS2_GET_DFS_REFERRAL;
|
|
ULONG InParameter, OutParameter, OutSetup, OutData;
|
|
PWCHAR pwsz;
|
|
|
|
RdrReferenceDiscardableCode(RdrFileDiscardableSection);
|
|
|
|
//
|
|
// The input buffer from Dfs contains the path name with the inconsistency
|
|
// followed by the DFS_REFERRAL_V1 that has the inconsistency. The
|
|
// path name is sent in the Parameter section, and the DFS_REFERRAL_V1 is
|
|
// passed in the Data section. So, parse these two things out.
|
|
//
|
|
|
|
for (pwsz = (PWCHAR) InputBuffer; *pwsz != UNICODE_NULL; pwsz++) {
|
|
NOTHING;
|
|
}
|
|
|
|
pwsz++; // Get past the NULL char
|
|
|
|
InParameter = (ULONG) (((PCHAR) pwsz) - ((PCHAR) InputBuffer));
|
|
|
|
if (InParameter >= InputBufferLength) {
|
|
return( STATUS_INVALID_PARAMETER );
|
|
}
|
|
|
|
OutParameter = 0;
|
|
OutSetup = 0;
|
|
OutData = 0;
|
|
|
|
if (!(Icb->Fcb->Connection->Server->Capabilities & DF_DFSAWARE)) {
|
|
|
|
Status = STATUS_DFS_UNAVAILABLE;
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
} else {
|
|
|
|
Status = RdrTransact(
|
|
Irp,
|
|
Icb->Fcb->Connection,
|
|
Icb->Se,
|
|
(PVOID) &GetReferralSetup,
|
|
sizeof(GetReferralSetup),
|
|
&OutSetup,
|
|
NULL,
|
|
InputBuffer,
|
|
InputBufferLength,
|
|
&OutParameter,
|
|
(PVOID) pwsz,
|
|
InputBufferLength - InParameter,
|
|
NULL,
|
|
&OutData,
|
|
&Icb->FileId,
|
|
0,
|
|
0,
|
|
0,
|
|
NULL,
|
|
NULL);
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
}
|
|
|
|
RdrDereferenceDiscardableCode(RdrFileDiscardableSection);
|
|
|
|
return( Status );
|
|
|
|
}
|
|
|
|
|
|
DBGSTATIC
|
|
NTSTATUS
|
|
RdrIssueNtIoctl(
|
|
IN BOOLEAN Wait,
|
|
IN BOOLEAN InFsd,
|
|
IN PIRP Irp,
|
|
IN PICB Icb,
|
|
IN ULONG Function,
|
|
IN PCHAR InputBuffer,
|
|
IN ULONG InputBufferLength,
|
|
IN PUCHAR OutputBuffer,
|
|
IN OUT PULONG OutputBufferLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine issues a remote FSCTL. All marshalling and
|
|
unmarshalling are the responsibility of the caller and
|
|
callee. This code tries to get the buffering right, but
|
|
it is best to use this only for METHOD_BUFFERED functions.
|
|
|
|
Arguments:
|
|
|
|
IN BOOLEAN Wait, - True IFF redirector can block callers thread on request
|
|
IN BOOLEAN InFsd,
|
|
IN PIRP Irp, - The Irp
|
|
IN PICB Icb,
|
|
IN Function,
|
|
IN PCHAR InputBuffer,
|
|
IN ULONG InputBufferLength,
|
|
IN PUCHAR OutputBuffer,
|
|
IN OUT PULONG OutputBufferLength
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
REQ_NT_IO_CONTROL Setup;
|
|
ULONG OutCount = sizeof(Setup);
|
|
ULONG ParCount = 0;
|
|
|
|
if (Icb->Fcb->Connection == NULL) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
} else if (!Wait) {
|
|
DbgBreakPoint();
|
|
Status = STATUS_UNEXPECTED_NETWORK_ERROR;
|
|
} else {
|
|
|
|
if( FlagOn( Icb->Flags, ICB_DEFERREDOPEN ) ) {
|
|
|
|
RdrAcquireFcbLock(Icb->Fcb, ExclusiveLock, TRUE);
|
|
|
|
if (FlagOn(Icb->Flags, ICB_DEFERREDOPEN) ) {
|
|
|
|
Status = RdrCreateFile(
|
|
Irp,
|
|
Icb,
|
|
Icb->u.d.OpenOptions,
|
|
Icb->u.d.ShareAccess,
|
|
Icb->u.d.FileAttributes,
|
|
Icb->u.d.DesiredAccess,
|
|
Icb->u.d.Disposition,
|
|
NULL,
|
|
FALSE);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
RdrReleaseFcbLock( Icb->Fcb );
|
|
return(Status);
|
|
}
|
|
}
|
|
|
|
RdrReleaseFcbLock( Icb->Fcb );
|
|
}
|
|
|
|
Setup.IsFsctl = TRUE;
|
|
|
|
SmbPutAlignedUlong(&Setup.FunctionCode, Function);
|
|
|
|
Setup.IsFlags = 0;
|
|
|
|
//
|
|
// If this is an FSCTL on a file that was pseudo-opened, we
|
|
// can't send the FSCTL because we don't have a file handle.
|
|
//
|
|
|
|
if (!FlagOn(Icb->Flags, ICB_HASHANDLE)) {
|
|
|
|
FILE_COMPRESSION_INFORMATION LocalBuffer;
|
|
ULONG Length;
|
|
|
|
//
|
|
// We can special-case FSCTL_GET_COMPRESSION because
|
|
// there is a path-based SMB that we can use to get
|
|
// the required information.
|
|
//
|
|
|
|
if (Function != FSCTL_GET_COMPRESSION) {
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
if (!ARGUMENT_PRESENT(OutputBuffer)) {
|
|
return STATUS_INVALID_USER_BUFFER;
|
|
}
|
|
if (*OutputBufferLength < sizeof(USHORT)) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
Length = sizeof(LocalBuffer);
|
|
Status = RdrQueryNtPathInformation(
|
|
NULL,
|
|
Icb,
|
|
SMB_QUERY_FILE_COMPRESSION_INFO,
|
|
&LocalBuffer,
|
|
&Length
|
|
);
|
|
if (NT_SUCCESS(Status)) {
|
|
Length = sizeof(USHORT);
|
|
try {
|
|
*(PUSHORT)OutputBuffer = LocalBuffer.CompressionFormat;
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
Status = GetExceptionCode();
|
|
Length = 0;
|
|
}
|
|
} else {
|
|
|
|
Length = 0;
|
|
|
|
//
|
|
// If the remote filesystem returned STATUS_INVALID_PARAMETER
|
|
// to our QueryInformationFile, meaning that it doesn't
|
|
// support compression, we need to translate that to the
|
|
// status the filesystem would return to the FSCTL --
|
|
// STATUS_INVALID_DEVICE_REQUEST.
|
|
//
|
|
|
|
if (Status == STATUS_INVALID_PARAMETER) {
|
|
Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
}
|
|
}
|
|
*OutputBufferLength = Length;
|
|
return Status;
|
|
|
|
}
|
|
|
|
SmbPutAlignedUshort(&Setup.Fid, Icb->FileId);
|
|
|
|
RdrReferenceDiscardableCode(RdrFileDiscardableSection);
|
|
|
|
Status = RdrTransact(Irp,
|
|
Icb->Fcb->Connection,
|
|
Icb->Se,
|
|
&Setup,
|
|
OutCount,
|
|
&OutCount,
|
|
NULL,
|
|
NULL,
|
|
ParCount,
|
|
&ParCount,
|
|
InputBuffer,
|
|
InputBufferLength,
|
|
OutputBuffer,
|
|
OutputBufferLength,
|
|
NULL,
|
|
0,
|
|
0,
|
|
NT_TRANSACT_IOCTL,
|
|
NULL,
|
|
NULL);
|
|
|
|
RdrDereferenceDiscardableCode(RdrFileDiscardableSection);
|
|
|
|
}
|
|
return(Status);
|
|
} // RdrIssueNtIoctl
|
|
|
|
|
|
|