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.
2416 lines
75 KiB
2416 lines
75 KiB
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
fsddisp.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the File System Driver for the LAN Manager
|
|
server.
|
|
|
|
Author:
|
|
|
|
David Treadwell (davidtr) 20-May-1990
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#include "wmikm.h"
|
|
#include <dfsfsctl.h>
|
|
#include "fsddisp.tmh"
|
|
#pragma hdrstop
|
|
|
|
#define BugCheckFileId SRV_FILE_FSDDISP
|
|
|
|
#define CHANGE_HEURISTIC(heuristic) \
|
|
(newValues->HeuristicsChangeMask & SRV_HEUR_ ## heuristic) != 0
|
|
|
|
//
|
|
// LWIO Context
|
|
//
|
|
PBYTE SrvLWIOContext = NULL;
|
|
ULONG SrvLWIOContextLength = 0;
|
|
PSRV_RESUME_CONTEXT_CALLBACK SrvLWIOCallback = NULL;
|
|
|
|
// Used for WMI event tracing
|
|
//
|
|
UNICODE_STRING SrvDeviceName;
|
|
UNICODE_STRING SrvRegistryPath;
|
|
ULONG SrvWmiInitialized = FALSE;
|
|
ULONG SrvWmiEnableLevel = 0;
|
|
ULONG SrvWmiEnableFlags = 0;
|
|
TRACEHANDLE LoggerHandle = 0;
|
|
|
|
GUID SrvCounterGuid = /* f7c3b22a-5992-44d6-968b-d3757dbab6f7 */
|
|
{ 0xf7c3b22a, 0x5992, 0x44d6, 0x96, 0x8b, 0xd3, 0x75, 0x7d, 0xba, 0xb6, 0xf7 };
|
|
GUID SrvControlGuid = /* 3121cf5d-c5e6-4f37-be86-57083590c333 */
|
|
{ 0x3121cf5d, 0xc5e6, 0x4f37, 0xbe, 0x86, 0x57, 0x08, 0x35, 0x90, 0xc3, 0x33 };
|
|
GUID SrvEventGuid = /* e09074ae-0a98-4805-9a41-a8940af97086 */
|
|
{ 0xe09074ae, 0x0a98, 0x4805, 0x9a, 0x41, 0xa8, 0x94, 0x0a, 0xf9, 0x70, 0x86 };
|
|
|
|
WMIGUIDREGINFO SrvPerfGuidList[] =
|
|
{
|
|
{ & SrvCounterGuid, 1, 0 },
|
|
{ & SrvControlGuid, 0, WMIREG_FLAG_TRACED_GUID
|
|
| WMIREG_FLAG_TRACE_CONTROL_GUID }
|
|
};
|
|
|
|
#define SrvPerfGuidCount (sizeof(SrvPerfGuidList) / sizeof(WMIGUIDREGINFO))
|
|
|
|
typedef struct _SRV_WMI_EVENT_TRACE {
|
|
EVENT_TRACE_HEADER EventHeader;
|
|
MOF_FIELD MofField[3];
|
|
} SRV_WMI_EVENT_TRACE, * PSRV_WMI_EVENT_TRACE;
|
|
|
|
//
|
|
// Forward declarations
|
|
//
|
|
|
|
STATIC
|
|
NTSTATUS
|
|
SrvFsdDispatchFsControl (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
);
|
|
|
|
VOID
|
|
QueueConfigurationIrp (
|
|
IN PIRP Irp,
|
|
IN PIO_WORKITEM pIoWorkItem
|
|
);
|
|
|
|
NTSTATUS
|
|
SrvQueryWmiRegInfo(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
OUT ULONG *RegFlags,
|
|
OUT PUNICODE_STRING InstanceName,
|
|
OUT PUNICODE_STRING *RegistryPath,
|
|
OUT PUNICODE_STRING MofResourceName,
|
|
OUT PDEVICE_OBJECT *Pdo
|
|
);
|
|
NTSTATUS
|
|
SrvQueryWmiDataBlock(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN ULONG GuidIndex,
|
|
IN ULONG InstanceIndex,
|
|
IN ULONG InstanceCount,
|
|
IN OUT PULONG InstanceLengthArray,
|
|
IN ULONG BufferAvail,
|
|
OUT PUCHAR Buffer
|
|
);
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text( PAGE, SrvFsdDispatch )
|
|
#pragma alloc_text( PAGE, SrvFsdDispatchFsControl )
|
|
#pragma alloc_text( PAGE, QueueConfigurationIrp )
|
|
#pragma alloc_text( PAGE, SrvWmiTraceEvent )
|
|
#pragma alloc_text( PAGE, SrvQueryWmiRegInfo )
|
|
#pragma alloc_text( PAGE, SrvQueryWmiDataBlock )
|
|
#pragma alloc_text( PAGE, SrvWmiDispatch )
|
|
#endif
|
|
|
|
// These 2 routines can be called at DISPATCH_LEVEL, so they are non-paged
|
|
// NONPAGED - SrvWmiStartContext
|
|
// NONPAGED - SrvWmiEndContext
|
|
|
|
void
|
|
SrvWmiInitContext(
|
|
PWORK_CONTEXT WorkContext
|
|
)
|
|
{
|
|
if (!SrvWmiInitialized || !(SrvWmiEnableFlags == SRV_WMI_FLAG_CAPACITY)) {
|
|
return;
|
|
}
|
|
|
|
if ( SRV_WMI_LEVEL( SPARSE ) ) {
|
|
WorkContext->PreviousSMB = EVENT_TYPE_SMB_LAST_EVENT;
|
|
WorkContext->bAlreadyTrace = FALSE;
|
|
WorkContext->ElapseKCPU = 0;
|
|
WorkContext->ElapseUCPU = 0;
|
|
WorkContext->FileNameSize = 0;
|
|
WorkContext->ClientAddr = 0;
|
|
WorkContext->FileObject = NULL;
|
|
WorkContext->G_StartTime.QuadPart =
|
|
(ULONGLONG) WmiGetClock(WMICT_DEFAULT, NULL);
|
|
}
|
|
}
|
|
|
|
void
|
|
SrvWmiStartContext(
|
|
PWORK_CONTEXT WorkContext
|
|
)
|
|
{
|
|
LARGE_INTEGER ThreadTime;
|
|
|
|
if (!SrvWmiInitialized || !(SrvWmiEnableFlags == SRV_WMI_FLAG_CAPACITY)) {
|
|
return;
|
|
}
|
|
|
|
if ( SRV_WMI_LEVEL( SPARSE ) ) {
|
|
if (WorkContext->G_StartTime.QuadPart == 0) {
|
|
WorkContext->G_StartTime.QuadPart =
|
|
(ULONGLONG) WmiGetClock(WMICT_DEFAULT, NULL);
|
|
}
|
|
}
|
|
|
|
if ( SRV_WMI_LEVEL( VERBOSE ) ) {
|
|
ThreadTime.QuadPart = (ULONGLONG) WmiGetClock(WMICT_THREAD, NULL);
|
|
WorkContext->KCPUStart = ThreadTime.HighPart;
|
|
WorkContext->UCPUStart = ThreadTime.LowPart;
|
|
}
|
|
}
|
|
|
|
void
|
|
SrvWmiEndContext(
|
|
PWORK_CONTEXT WorkContext
|
|
)
|
|
{
|
|
LARGE_INTEGER TimeEnd;
|
|
BOOL NotDispatch = (KeGetCurrentIrql() < DISPATCH_LEVEL);
|
|
|
|
if (!SrvWmiInitialized || !(SrvWmiEnableFlags == SRV_WMI_FLAG_CAPACITY)) {
|
|
return;
|
|
}
|
|
|
|
if ( SRV_WMI_LEVEL( SPARSE ) ) {
|
|
if ( NotDispatch && WorkContext && WorkContext->Rfcb && WorkContext->Rfcb->Lfcb) {
|
|
WorkContext->FileObject = WorkContext->Rfcb->Lfcb->FileObject;
|
|
}
|
|
}
|
|
|
|
if ( SRV_WMI_LEVEL( VERBOSE ) ) {
|
|
TimeEnd.QuadPart = (ULONGLONG) WmiGetClock(WMICT_THREAD, NULL);
|
|
WorkContext->ElapseKCPU = TimeEnd.HighPart - WorkContext->KCPUStart;
|
|
WorkContext->ElapseUCPU = TimeEnd.LowPart - WorkContext->UCPUStart;
|
|
|
|
if( NotDispatch )
|
|
{
|
|
if (WorkContext && WorkContext->Rfcb
|
|
&& WorkContext->Rfcb->Lfcb
|
|
&& WorkContext->Rfcb->Lfcb->Mfcb
|
|
&& WorkContext->Rfcb->Lfcb->Mfcb->FileName.Buffer
|
|
&& WorkContext->Rfcb->Lfcb->Mfcb->FileName.Length > 0)
|
|
{
|
|
LPWSTR strFileName = WorkContext->Rfcb->Lfcb->Mfcb->FileName.Buffer;
|
|
WorkContext->FileNameSize =
|
|
(USHORT) ((wcslen(strFileName) + 1) * sizeof(WCHAR));
|
|
if (WorkContext->FileNameSize > 1024 * sizeof(WCHAR)) {
|
|
WorkContext->FileNameSize = 1024 * sizeof(WCHAR);
|
|
}
|
|
RtlCopyMemory(WorkContext->strFileName,
|
|
strFileName,
|
|
WorkContext->FileNameSize);
|
|
WorkContext->strFileName[1023] = L'\0';
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WorkContext->strFileName[0] = L'\0';
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
SrvWmiTraceEvent(
|
|
PWORK_CONTEXT WorkContext
|
|
)
|
|
{
|
|
|
|
PAGED_CODE();
|
|
|
|
if (!SrvWmiInitialized || !(SrvWmiEnableFlags == SRV_WMI_FLAG_CAPACITY)) {
|
|
return;
|
|
}
|
|
|
|
if ( SRV_WMI_LEVEL( SPARSE ) ) {
|
|
NTSTATUS status;
|
|
SRV_WMI_EVENT_TRACE Wnode;
|
|
|
|
if (WorkContext->PreviousSMB >= EVENT_TYPE_SMB_LAST_EVENT) {
|
|
return;
|
|
}
|
|
|
|
if (WorkContext->Connection->DirectHostIpx) {
|
|
WorkContext->ClientAddr =
|
|
WorkContext->Connection->IpxAddress.NetworkAddress;
|
|
}
|
|
else {
|
|
WorkContext->ClientAddr =
|
|
WorkContext->Connection->ClientIPAddress;
|
|
}
|
|
|
|
RtlZeroMemory(& Wnode, sizeof(SRV_WMI_EVENT_TRACE));
|
|
if (WorkContext->FileNameSize > 0) {
|
|
Wnode.EventHeader.Size = sizeof(SRV_WMI_EVENT_TRACE);
|
|
}
|
|
else {
|
|
Wnode.EventHeader.Size = sizeof(EVENT_TRACE_HEADER)
|
|
+ sizeof(MOF_FIELD);
|
|
}
|
|
Wnode.EventHeader.Flags = WNODE_FLAG_TRACED_GUID
|
|
| WNODE_FLAG_USE_GUID_PTR
|
|
| WNODE_FLAG_USE_MOF_PTR;
|
|
Wnode.EventHeader.GuidPtr = (ULONGLONG) & SrvEventGuid;
|
|
Wnode.EventHeader.Class.Type = WorkContext->PreviousSMB;
|
|
|
|
((PWNODE_HEADER) (& Wnode.EventHeader))->HistoricalContext =
|
|
LoggerHandle;
|
|
|
|
Wnode.MofField[0].Length = sizeof(LARGE_INTEGER) // G_StartTime
|
|
+ sizeof(ULONG) // ElapseKCPU
|
|
+ sizeof(ULONG) // ElapseUCPU
|
|
+ sizeof(ULONG) // ClientAddr
|
|
+ sizeof(PFILE_OBJECT); // FileObject
|
|
Wnode.MofField[0].DataPtr = (ULONGLONG) (& WorkContext->G_StartTime);
|
|
|
|
if (WorkContext->FileNameSize > 0) {
|
|
Wnode.MofField[1].Length = sizeof(USHORT);
|
|
Wnode.MofField[1].DataPtr =
|
|
(ULONGLONG) (& WorkContext->FileNameSize);
|
|
Wnode.MofField[2].Length = WorkContext->FileNameSize;
|
|
Wnode.MofField[2].DataPtr =
|
|
(ULONGLONG) (WorkContext->strFileName);
|
|
}
|
|
|
|
// Call TraceLogger to write this event
|
|
//
|
|
status = IoWMIWriteEvent((PVOID) & Wnode);
|
|
if (!NT_SUCCESS(status)) {
|
|
DbgPrint("SrvWmiTraceEvent(0x%08X,%d) fails 0x%08X\n",
|
|
WorkContext, WorkContext->PreviousSMB, status);
|
|
}
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
SrvQueryWmiRegInfo(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
OUT ULONG *RegFlags,
|
|
OUT PUNICODE_STRING InstanceName,
|
|
OUT PUNICODE_STRING *RegistryPath,
|
|
OUT PUNICODE_STRING MofResourceName,
|
|
OUT PDEVICE_OBJECT *Pdo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is a callback into the driver to retrieve information about
|
|
the guids being registered.
|
|
|
|
Implementations of this routine may be in paged memory
|
|
|
|
Arguments:
|
|
|
|
DeviceObject is the device whose registration information is needed
|
|
|
|
*RegFlags returns with a set of flags that describe all of the guids being
|
|
registered for this device. If the device wants enable and disable
|
|
collection callbacks before receiving queries for the registered
|
|
guids then it should return the WMIREG_FLAG_EXPENSIVE flag. Also the
|
|
returned flags may specify WMIREG_FLAG_INSTANCE_PDO in which case
|
|
the instance name is determined from the PDO associated with the
|
|
device object. Note that the PDO must have an associated devnode. If
|
|
WMIREG_FLAG_INSTANCE_PDO is not set then Name must return a unique
|
|
name for the device. These flags are ORed into the flags specified
|
|
by the GUIDREGINFO for each guid.
|
|
|
|
InstanceName returns with the instance name for the guids if
|
|
WMIREG_FLAG_INSTANCE_PDO is not set in the returned *RegFlags. The
|
|
caller will call ExFreePool with the buffer returned.
|
|
|
|
*RegistryPath returns with the registry path of the driver. This is
|
|
required
|
|
|
|
MofResourceName returns with the name of the MOF resource attached to
|
|
the binary file. If the driver does not have a mof resource attached
|
|
then this can be returned unmodified. If a value is returned then
|
|
it is NOT freed.
|
|
The MOF file is assumed to be already included in wmicore.mof
|
|
|
|
*Pdo returns with the device object for the PDO associated with this
|
|
device if the WMIREG_FLAG_INSTANCE_PDO flag is retured in
|
|
*RegFlags.
|
|
|
|
Return Value:
|
|
|
|
status
|
|
|
|
--*/
|
|
{
|
|
PDEVICE_EXTENSION pDeviceExtension = (PDEVICE_EXTENSION)
|
|
DeviceObject->DeviceExtension;
|
|
PAGED_CODE();
|
|
|
|
if (! SrvWmiInitialized) {
|
|
return STATUS_DEVICE_NOT_READY;
|
|
}
|
|
|
|
pDeviceExtension->TestCounter ++;
|
|
|
|
* RegFlags = WMIREG_FLAG_EXPENSIVE;
|
|
InstanceName->MaximumLength = SrvDeviceName.Length
|
|
+ sizeof(UNICODE_NULL);
|
|
InstanceName->Buffer = ExAllocatePool(PagedPool,
|
|
InstanceName->MaximumLength);
|
|
if (InstanceName->Buffer != NULL) {
|
|
InstanceName->Length = InstanceName->MaximumLength
|
|
- sizeof(UNICODE_NULL);
|
|
RtlCopyUnicodeString(InstanceName, & SrvDeviceName);
|
|
}
|
|
else {
|
|
InstanceName->MaximumLength = InstanceName->Length = 0;
|
|
}
|
|
|
|
MofResourceName->MaximumLength = 0;
|
|
MofResourceName->Length = 0;
|
|
MofResourceName->Buffer = NULL;
|
|
|
|
* RegistryPath = & SrvRegistryPath;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
SrvQueryWmiDataBlock(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN ULONG GuidIndex,
|
|
IN ULONG InstanceIndex,
|
|
IN ULONG InstanceCount,
|
|
IN OUT PULONG InstanceLengthArray,
|
|
IN ULONG BufferAvail,
|
|
OUT PUCHAR Buffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is a callback into the driver to query for the contents of
|
|
all instances of a data block. When the driver has finished filling the
|
|
data block it must call WmiCompleteRequest to complete the irp. The
|
|
driver can return STATUS_PENDING if the irp cannot be completed
|
|
immediately.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject is the device whose data block is being queried
|
|
|
|
Irp is the Irp that makes this request
|
|
|
|
GuidIndex is the index into the list of guids provided when the
|
|
device registered
|
|
|
|
InstanceCount is the number of instnaces expected to be returned for
|
|
the data block.
|
|
|
|
InstanceLengthArray is a pointer to an array of ULONG that returns the
|
|
lengths of each instance of the data block. If this is NULL then
|
|
there was not enough space in the output buffer to fufill the request
|
|
so the irp should be completed with the buffer needed.
|
|
|
|
BufferAvail on entry has the maximum size available to write the data
|
|
blocks.
|
|
|
|
Buffer on return is filled with the returned data blocks. Note that each
|
|
instance of the data block must be aligned on a 8 byte boundry.
|
|
|
|
|
|
Return Value:
|
|
|
|
status
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PDEVICE_EXTENSION pDeviceExtension = (PDEVICE_EXTENSION)
|
|
DeviceObject->DeviceExtension;
|
|
ULONG SizeNeeded = sizeof(ULONG);
|
|
|
|
PAGED_CODE();
|
|
|
|
if (! SrvWmiInitialized) {
|
|
return STATUS_DEVICE_NOT_READY;
|
|
}
|
|
|
|
pDeviceExtension->TestCounter ++;
|
|
|
|
if (GuidIndex == 0) {
|
|
* InstanceLengthArray = SizeNeeded;
|
|
* ((PULONG) Buffer) = pDeviceExtension->TestCounter;
|
|
}
|
|
else {
|
|
Status = STATUS_WMI_GUID_NOT_FOUND;
|
|
}
|
|
|
|
Status = WmiCompleteRequest(DeviceObject,
|
|
Irp,
|
|
Status,
|
|
SizeNeeded,
|
|
IO_NO_INCREMENT);
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
SrvWmiDispatch(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
ULONG BufferSize = irpSp->Parameters.WMI.BufferSize;
|
|
PVOID Buffer = irpSp->Parameters.WMI.Buffer;
|
|
ULONG ReturnSize = 0;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PWNODE_HEADER pWnode = NULL;
|
|
PDEVICE_EXTENSION pDeviceExtension = (PDEVICE_EXTENSION)
|
|
DeviceObject->DeviceExtension;
|
|
SYSCTL_IRP_DISPOSITION disposition;
|
|
|
|
PAGED_CODE();
|
|
|
|
switch (irpSp->MinorFunction) {
|
|
case IRP_MN_ENABLE_EVENTS:
|
|
pWnode = (PWNODE_HEADER) Buffer;
|
|
if (BufferSize >= sizeof(WNODE_HEADER)) {
|
|
LoggerHandle = pWnode->HistoricalContext;
|
|
InterlockedExchange(& SrvWmiEnableLevel,
|
|
((PTRACE_ENABLE_CONTEXT) (& LoggerHandle))->Level + 1);
|
|
InterlockedExchange(& SrvWmiEnableFlags,
|
|
((PTRACE_ENABLE_CONTEXT) (& LoggerHandle))->EnableFlags );
|
|
}
|
|
Irp->IoStatus.Status = Status;
|
|
Irp->IoStatus.Information = ReturnSize;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
break;
|
|
|
|
case IRP_MN_DISABLE_EVENTS:
|
|
InterlockedExchange(& SrvWmiEnableLevel, 0);
|
|
LoggerHandle = 0;
|
|
Irp->IoStatus.Status = Status;
|
|
Irp->IoStatus.Information = ReturnSize;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
break;
|
|
|
|
default:
|
|
Status = WmiSystemControl(& pDeviceExtension->WmiLibContext,
|
|
DeviceObject,
|
|
Irp,
|
|
& disposition);
|
|
switch(disposition) {
|
|
case IrpProcessed:
|
|
break;
|
|
|
|
case IrpNotCompleted:
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
break;
|
|
|
|
case IrpForward:
|
|
case IrpNotWmi:
|
|
default:
|
|
ASSERT(FALSE);
|
|
Irp->IoStatus.Status = Status = STATUS_NOT_SUPPORTED;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SrvFsdDispatch (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the dispatch routine for the LAN Manager server FSD. At the
|
|
present time, the server FSD does not accept any I/O requests.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Pointer to device object for target device
|
|
|
|
Irp - Pointer to I/O request packet
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS -- Indicates whether the request was successfully queued.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
PIO_STACK_LOCATION irpSp;
|
|
PIO_WORKITEM pWorkItem;
|
|
|
|
PAGED_CODE( );
|
|
|
|
DeviceObject; // prevent compiler warnings
|
|
|
|
if( SrvSvcProcess == NULL &&
|
|
SeSinglePrivilegeCheck( SeExports->SeLoadDriverPrivilege, Irp->RequestorMode ) ) {
|
|
|
|
//
|
|
// This is the first fsctl to the server from a process having
|
|
// driver load/unload privileges -- it must be from
|
|
// the service controller. Remember the process id of the
|
|
// service controller to validate future fsctls
|
|
//
|
|
|
|
SrvSvcProcess = IoGetCurrentProcess();
|
|
}
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation( Irp );
|
|
|
|
#if defined( _WIN64 )
|
|
// There is no reason for us to support downlevel clients because all communication with the
|
|
// server (that is not network packets) goes through the Server Service via RPC resulting in
|
|
// it being serialized and interpreted correctly. If we get IOCTL's called directly, it must
|
|
// be a hack attempt, so we're free to turn it away.
|
|
|
|
// It ends up we do need to support some 32-bit functionality for old perf monitoring utilities. Allow
|
|
// through Create,Cleanup,Close, and the GetStatistics FSCTL's.
|
|
if ( IoIs32bitProcess( Irp ) )
|
|
{
|
|
switch( irpSp->MajorFunction )
|
|
{
|
|
case IRP_MJ_CREATE:
|
|
case IRP_MJ_CLEANUP:
|
|
case IRP_MJ_CLOSE:
|
|
break;
|
|
|
|
case IRP_MJ_FILE_SYSTEM_CONTROL:
|
|
{
|
|
if( !( (irpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_SRV_GET_STATISTICS) ||
|
|
(irpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_SRV_GET_QUEUE_STATISTICS) ) )
|
|
{
|
|
status = STATUS_NOT_SUPPORTED;
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest( Irp, 2 );
|
|
return status;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
{
|
|
status = STATUS_NOT_SUPPORTED;
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest( Irp, 2 );
|
|
return status;
|
|
}
|
|
|
|
}
|
|
}
|
|
#endif
|
|
|
|
switch ( irpSp->MajorFunction ) {
|
|
|
|
case IRP_MJ_CREATE:
|
|
|
|
FsRtlEnterFileSystem();
|
|
ACQUIRE_LOCK( &SrvConfigurationLock );
|
|
|
|
do {
|
|
|
|
if( SrvOpenCount == 0 ) {
|
|
//
|
|
// This is the first open. Let's not allow it if the server
|
|
// seems to be in a weird state.
|
|
//
|
|
if( SrvFspActive != FALSE || SrvFspTransitioning != FALSE ) {
|
|
//
|
|
// How can this be? Better not let anybody in, since we're sick
|
|
//
|
|
status = STATUS_ACCESS_DENIED;
|
|
break;
|
|
}
|
|
|
|
} else if( SrvFspActive && SrvFspTransitioning ) {
|
|
//
|
|
// We currently have some open handles, but
|
|
// we are in the middle of terminating. Don't let new
|
|
// opens in
|
|
//
|
|
status = STATUS_ACCESS_DENIED;
|
|
break;
|
|
}
|
|
|
|
SrvOpenCount++;
|
|
|
|
} while( 0 );
|
|
|
|
RELEASE_LOCK( &SrvConfigurationLock );
|
|
FsRtlExitFileSystem();
|
|
|
|
break;
|
|
|
|
case IRP_MJ_CLEANUP:
|
|
|
|
break;
|
|
|
|
case IRP_MJ_CLOSE:
|
|
FsRtlEnterFileSystem();
|
|
ACQUIRE_LOCK( &SrvConfigurationLock );
|
|
if( --SrvOpenCount == 0 ) {
|
|
if( SrvFspActive && !SrvFspTransitioning ) {
|
|
//
|
|
// Uh oh. This is our last close, and we think
|
|
// we're still running. We can't run sensibly
|
|
// without srvsvc to help out. Suicide time!
|
|
//
|
|
pWorkItem = IoAllocateWorkItem( SrvDeviceObject );
|
|
if( !pWorkItem )
|
|
{
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
RELEASE_LOCK( &SrvConfigurationLock );
|
|
FsRtlExitFileSystem();
|
|
goto exit;
|
|
}
|
|
|
|
SrvXsActive = FALSE;
|
|
SrvFspTransitioning = TRUE;
|
|
IoMarkIrpPending( Irp );
|
|
QueueConfigurationIrp( Irp, pWorkItem );
|
|
RELEASE_LOCK( &SrvConfigurationLock );
|
|
status = STATUS_PENDING;
|
|
FsRtlExitFileSystem();
|
|
goto exit;
|
|
}
|
|
}
|
|
RELEASE_LOCK( &SrvConfigurationLock );
|
|
FsRtlExitFileSystem();
|
|
break;
|
|
|
|
case IRP_MJ_FILE_SYSTEM_CONTROL:
|
|
|
|
status = SrvFsdDispatchFsControl( DeviceObject, Irp, irpSp );
|
|
goto exit;
|
|
|
|
case IRP_MJ_SYSTEM_CONTROL:
|
|
if (SrvWmiInitialized) {
|
|
status = SrvWmiDispatch(DeviceObject, Irp);
|
|
goto exit;
|
|
}
|
|
// else fall through default processing
|
|
//
|
|
|
|
default:
|
|
|
|
IF_DEBUG(ERRORS) {
|
|
SrvPrint1(
|
|
"SrvFsdDispatch: Invalid major function %lx\n",
|
|
irpSp->MajorFunction
|
|
);
|
|
}
|
|
status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
}
|
|
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest( Irp, 2 );
|
|
|
|
exit:
|
|
|
|
return status;
|
|
|
|
} // SrvFsdDispatch
|
|
|
|
|
|
NTSTATUS
|
|
SrvFsdDispatchFsControl (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles device IO control requests to the server,
|
|
including starting the server, stopping the server, and more.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Pointer to device object for target device
|
|
|
|
Irp - Pointer to I/O request packet
|
|
|
|
IrpSp - Pointer to the current IRP stack location
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS -- Indicates whether the request was successfully handled.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
ULONG code;
|
|
PIO_WORKITEM pWorkItem;
|
|
|
|
DeviceObject; // prevent compiler warnings
|
|
|
|
//
|
|
// Initialize the I/O status block.
|
|
//
|
|
|
|
Irp->IoStatus.Status = STATUS_PENDING;
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
FsRtlEnterFileSystem();
|
|
|
|
//
|
|
// Process the request if possible.
|
|
//
|
|
|
|
code = IrpSp->Parameters.FileSystemControl.FsControlCode;
|
|
|
|
//
|
|
// Only the serice controller can issue most of the FSCTL requests.
|
|
//
|
|
if( Irp->RequestorMode != KernelMode &&
|
|
IoGetCurrentProcess() != SrvSvcProcess ) {
|
|
|
|
if( code != FSCTL_SRV_SEND_DATAGRAM &&
|
|
code != FSCTL_SRV_GET_QUEUE_STATISTICS &&
|
|
code != FSCTL_SRV_GET_STATISTICS &&
|
|
code != FSCTL_SRV_IPX_SMART_CARD_START &&
|
|
code != FSCTL_SRV_GET_CHALLENGE &&
|
|
code != FSCTL_SRV_INTERNAL_TEST_REAUTH &&
|
|
code != FSCTL_SRV_QUERY_LWIO_CONTEXT &&
|
|
code != FSCTL_SRV_SET_LWIO_CONTEXT &&
|
|
code != FSCTL_SRV_REQUEST_HANDLE_DUP &&
|
|
code != FSCTL_DFS_UPDATE_SHARE_TABLE &&
|
|
code != FSCTL_DFS_RELEASE_SHARE_TABLE ) {
|
|
|
|
status = STATUS_ACCESS_DENIED;
|
|
goto exit_without_lock;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Acquire the configuration lock.
|
|
//
|
|
ACQUIRE_LOCK( &SrvConfigurationLock );
|
|
|
|
switch ( code ) {
|
|
|
|
case FSCTL_SRV_STARTUP: {
|
|
|
|
PSERVER_REQUEST_PACKET srp;
|
|
ULONG srpLength;
|
|
PVOID inputBuffer;
|
|
ULONG inputBufferLength;
|
|
PMDL InputMdl = NULL;
|
|
|
|
PDEVICE_EXTENSION pDeviceExtension;
|
|
PWMILIB_CONTEXT pWmiLibContext;
|
|
|
|
//
|
|
// Get a pointer to the SRP that describes the set info request
|
|
// for the startup server configuration, and the buffer that
|
|
// contains this information.
|
|
//
|
|
|
|
srp = IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
|
|
srpLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
|
|
inputBuffer = Irp->UserBuffer;
|
|
inputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
|
|
|
|
//
|
|
// If the server FSP is already started, or is in the process of
|
|
// starting up, reject this request.
|
|
//
|
|
|
|
if ( SrvFspActive || SrvFspTransitioning ) {
|
|
|
|
//IF_DEBUG(ERRORS) {
|
|
// SrvPrint0( "LAN Manager server FSP already started.\n" );
|
|
//}
|
|
|
|
try {
|
|
status = STATUS_SUCCESS;
|
|
srp->ErrorCode = NERR_ServiceInstalled;
|
|
}
|
|
except( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
goto exit_with_lock;
|
|
}
|
|
|
|
//
|
|
// Make sure that the buffer was large enough to be an SRP.
|
|
//
|
|
|
|
if ( srpLength < sizeof(SERVER_REQUEST_PACKET) ) {
|
|
status = STATUS_INVALID_PARAMETER;
|
|
goto exit_with_lock;
|
|
}
|
|
|
|
// SRP is unused by the below routine. Remove its parsing to lower attack surface
|
|
|
|
//
|
|
// Lets lock the input data into memory
|
|
//
|
|
InputMdl = IoAllocateMdl( inputBuffer, inputBufferLength, FALSE, TRUE, NULL );
|
|
if( InputMdl == NULL )
|
|
{
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto exit_with_lock;
|
|
}
|
|
|
|
try {
|
|
MmProbeAndLockPages( InputMdl, Irp->RequestorMode, IoReadAccess );
|
|
}
|
|
except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
status = STATUS_INVALID_PARAMETER;
|
|
IoFreeMdl( InputMdl );
|
|
goto exit_with_lock;
|
|
}
|
|
|
|
//
|
|
// Call SrvNetServerSetInfo to set the initial server configuration
|
|
// information.
|
|
//
|
|
|
|
status = SrvNetServerSetInfo(
|
|
NULL,
|
|
inputBuffer,
|
|
inputBufferLength
|
|
);
|
|
|
|
MmUnlockPages( InputMdl );
|
|
IoFreeMdl( InputMdl );
|
|
|
|
//
|
|
// Indicate that the server is starting up. This prevents
|
|
// further startup requests from being issued.
|
|
//
|
|
|
|
SrvFspTransitioning = TRUE;
|
|
|
|
// Setup device extension for Perf counter registration and register
|
|
// with WMI here
|
|
//
|
|
pDeviceExtension = (PDEVICE_EXTENSION) SrvDeviceObject->DeviceExtension;
|
|
RtlZeroMemory(pDeviceExtension, sizeof(DEVICE_EXTENSION));
|
|
pDeviceExtension->pDeviceObject = SrvDeviceObject;
|
|
|
|
pWmiLibContext = & pDeviceExtension->WmiLibContext;
|
|
RtlZeroMemory(pWmiLibContext, sizeof(WMILIB_CONTEXT));
|
|
pWmiLibContext->GuidCount = SrvPerfGuidCount;
|
|
pWmiLibContext->GuidList = SrvPerfGuidList;
|
|
pWmiLibContext->QueryWmiDataBlock = SrvQueryWmiDataBlock;
|
|
pWmiLibContext->QueryWmiRegInfo = SrvQueryWmiRegInfo;
|
|
|
|
SrvWmiInitialized = TRUE;
|
|
status = IoWMIRegistrationControl(
|
|
SrvDeviceObject, WMIREG_ACTION_REGISTER);
|
|
if (!NT_SUCCESS(status)) {
|
|
DbgPrint("SRV: Failed to register for WMI support\n");
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case FSCTL_SRV_SHUTDOWN: {
|
|
|
|
//
|
|
// If the server is not running, or if it is in the process
|
|
// of shutting down, ignore this request.
|
|
//
|
|
|
|
if ( !SrvFspActive || SrvFspTransitioning ) {
|
|
|
|
//
|
|
// If there is more than one handle open to the server
|
|
// device (i.e., any handles other than the server service's
|
|
// handle), return a special status code to the caller (who
|
|
// should be the server service). This tells the caller to
|
|
// NOT unload the driver, in order prevent weird situations
|
|
// where the driver is sort of unloaded, so it can't be used
|
|
// but also can't be reloaded, thus preventing the server
|
|
// from being restarted.
|
|
//
|
|
|
|
if ( SrvOpenCount != 1 ) {
|
|
status = STATUS_SERVER_HAS_OPEN_HANDLES;
|
|
} else {
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
|
|
goto exit_with_lock;
|
|
|
|
}
|
|
|
|
//
|
|
// Indicate that the server is shutting down. This prevents
|
|
// further requests from being issued until the server is
|
|
// restarted.
|
|
//
|
|
|
|
SrvFspTransitioning = TRUE;
|
|
|
|
break;
|
|
}
|
|
|
|
case FSCTL_SRV_REGISTRY_CHANGE:
|
|
case FSCTL_SRV_BEGIN_PNP_NOTIFICATIONS:
|
|
case FSCTL_SRV_XACTSRV_CONNECT:
|
|
{
|
|
if( !SrvFspActive || SrvFspTransitioning ) {
|
|
//IF_DEBUG(ERRORS) {
|
|
// SrvPrint0( "LAN Manager server FSP not started.\n" );
|
|
//}
|
|
status = STATUS_SERVER_NOT_STARTED;
|
|
goto exit_with_lock;
|
|
}
|
|
break;
|
|
}
|
|
case FSCTL_SRV_XACTSRV_DISCONNECT: {
|
|
|
|
//
|
|
// If the server is not running, or if it is in the process
|
|
// of shutting down, ignore this request.
|
|
//
|
|
|
|
if ( !SrvFspActive || SrvFspTransitioning ) {
|
|
|
|
//IF_DEBUG(ERRORS) {
|
|
// SrvPrint0( "LAN Manager server FSP not started.\n" );
|
|
//}
|
|
|
|
status = STATUS_SUCCESS;
|
|
goto exit_with_lock;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case FSCTL_SRV_IPX_SMART_CARD_START: {
|
|
|
|
//
|
|
// If the server is not running, or if it is in the process of
|
|
// shutting down, ignore this request.
|
|
//
|
|
if( !SrvFspActive || SrvFspTransitioning ) {
|
|
status = STATUS_SERVER_NOT_STARTED;
|
|
goto exit_with_lock;
|
|
}
|
|
|
|
//
|
|
// Make sure the caller is a driver
|
|
//
|
|
if( Irp->RequestorMode != KernelMode ) {
|
|
status = STATUS_ACCESS_DENIED;
|
|
goto exit_with_lock;
|
|
}
|
|
|
|
//
|
|
// Make sure the buffer is big enough
|
|
//
|
|
if( IrpSp->Parameters.FileSystemControl.InputBufferLength <
|
|
sizeof( SrvIpxSmartCard ) ) {
|
|
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
goto exit_with_lock;
|
|
}
|
|
|
|
if( SrvIpxSmartCard.Open == NULL ) {
|
|
|
|
PSRV_IPX_SMART_CARD pSipx;
|
|
|
|
//
|
|
// Load up the pointers
|
|
//
|
|
|
|
pSipx = (PSRV_IPX_SMART_CARD)(Irp->AssociatedIrp.SystemBuffer);
|
|
|
|
if( pSipx == NULL ) {
|
|
status = STATUS_INVALID_PARAMETER;
|
|
goto exit_with_lock;
|
|
}
|
|
|
|
if( pSipx->Read && pSipx->Close && pSipx->DeRegister && pSipx->Open ) {
|
|
|
|
IF_DEBUG( SIPX ) {
|
|
KdPrint(( "Accepting entry points for IPX Smart Card:\n" ));
|
|
KdPrint(( " Open %p, Read %p, Close %p, DeRegister %p",
|
|
SrvIpxSmartCard.Open,
|
|
SrvIpxSmartCard.Read,
|
|
SrvIpxSmartCard.Close,
|
|
SrvIpxSmartCard.DeRegister
|
|
));
|
|
}
|
|
|
|
//
|
|
// First set our entry point
|
|
//
|
|
pSipx->ReadComplete = SrvIpxSmartCardReadComplete;
|
|
|
|
//
|
|
// Now accept the card's entry points.
|
|
//
|
|
SrvIpxSmartCard.Read = pSipx->Read;
|
|
SrvIpxSmartCard.Close= pSipx->Close;
|
|
SrvIpxSmartCard.DeRegister = pSipx->DeRegister;
|
|
SrvIpxSmartCard.Open = pSipx->Open;
|
|
|
|
status = STATUS_SUCCESS;
|
|
} else {
|
|
status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
} else {
|
|
|
|
status = STATUS_DEVICE_ALREADY_ATTACHED;
|
|
}
|
|
|
|
goto exit_with_lock;
|
|
|
|
break;
|
|
}
|
|
|
|
case FSCTL_SRV_SEND_DATAGRAM:
|
|
{
|
|
PVOID systemBuffer;
|
|
ULONG systemBufferLength;
|
|
PVOID buffer1;
|
|
ULONG buffer1Length;
|
|
PVOID buffer2;
|
|
ULONG buffer2Length;
|
|
PSERVER_REQUEST_PACKET srp;
|
|
|
|
//
|
|
// Ignore this request if the server is not active.
|
|
//
|
|
|
|
if ( !SrvFspActive || SrvFspTransitioning ) {
|
|
status = STATUS_SUCCESS;
|
|
goto exit_with_lock;
|
|
}
|
|
|
|
|
|
//
|
|
// Determine the input buffer lengths, and make sure that the
|
|
// first buffer is large enough to be an SRP.
|
|
//
|
|
|
|
buffer1Length = IrpSp->Parameters.FileSystemControl.InputBufferLength;
|
|
buffer2Length = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
|
|
|
|
//
|
|
// Make sure that the buffer was large enough to be a SRP.
|
|
//
|
|
if ( buffer1Length < sizeof(SERVER_REQUEST_PACKET) ) {
|
|
status = STATUS_INVALID_PARAMETER;
|
|
goto exit_with_lock;
|
|
}
|
|
|
|
// Make sure the lengths are nominally reasonable.
|
|
//
|
|
if( buffer1Length >= MAXUSHORT ||
|
|
buffer2Length >= MAXUSHORT ) {
|
|
|
|
status = STATUS_INVALID_PARAMETER;
|
|
goto exit_with_lock;
|
|
}
|
|
|
|
//
|
|
// Make the first buffer size is properly aligned so that the second
|
|
// buffer will be aligned as well.
|
|
//
|
|
|
|
buffer1Length = ALIGN_UP( buffer1Length, PVOID );
|
|
systemBufferLength = buffer1Length + buffer2Length;
|
|
|
|
//
|
|
// Make sure the lengths are nominally reasonable.
|
|
//
|
|
if( buffer1Length >= MAXUSHORT ||
|
|
buffer2Length >= MAXUSHORT ||
|
|
systemBufferLength == 0 ) {
|
|
|
|
status = STATUS_INVALID_PARAMETER;
|
|
goto exit_with_lock;
|
|
}
|
|
|
|
if( Irp->RequestorMode != KernelMode ) {
|
|
try {
|
|
|
|
ProbeForRead( IrpSp->Parameters.FileSystemControl.Type3InputBuffer,
|
|
buffer1Length, sizeof( CHAR )
|
|
);
|
|
|
|
if( buffer2Length ) {
|
|
ProbeForRead( Irp->UserBuffer, buffer2Length, sizeof( CHAR ) );
|
|
}
|
|
|
|
} except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
status = GetExceptionCode();
|
|
goto exit_with_lock;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Allocate a single buffer that will hold both input buffers.
|
|
//
|
|
|
|
systemBuffer = ExAllocatePoolWithTagPriority( PagedPool, systemBufferLength, TAG_FROM_TYPE(BlockTypeMisc), LowPoolPriority );
|
|
|
|
if ( systemBuffer == NULL ) {
|
|
status = STATUS_INSUFF_SERVER_RESOURCES;
|
|
goto exit_with_lock;
|
|
}
|
|
|
|
buffer1 = systemBuffer;
|
|
buffer2 = (PCHAR)systemBuffer + buffer1Length;
|
|
|
|
//
|
|
// Copy the information into the buffers.
|
|
//
|
|
|
|
try {
|
|
|
|
RtlCopyMemory(
|
|
buffer1,
|
|
IrpSp->Parameters.FileSystemControl.Type3InputBuffer,
|
|
IrpSp->Parameters.FileSystemControl.InputBufferLength
|
|
);
|
|
if ( buffer2Length > 0 ) {
|
|
RtlCopyMemory( buffer2, Irp->UserBuffer, buffer2Length );
|
|
}
|
|
|
|
} except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
status = GetExceptionCode();
|
|
ExFreePool( buffer1 );
|
|
goto exit_with_lock;
|
|
}
|
|
|
|
//
|
|
// If a name was specified in the SRP, the buffer field will
|
|
// contain an offset rather than a pointer. Convert the offset
|
|
// to a pointer and verify that that it is a legal pointer.
|
|
//
|
|
|
|
srp = buffer1;
|
|
|
|
OFFSET_TO_POINTER( srp->Name1.Buffer, srp );
|
|
|
|
if ( !POINTER_IS_VALID( srp->Name1.Buffer, srp, buffer1Length ) ) {
|
|
status = STATUS_ACCESS_VIOLATION;
|
|
ExFreePool( buffer1 );
|
|
goto exit_with_lock;
|
|
}
|
|
|
|
OFFSET_TO_POINTER( srp->Name2.Buffer, srp );
|
|
|
|
if ( !POINTER_IS_VALID( srp->Name2.Buffer, srp, buffer1Length ) ) {
|
|
status = STATUS_ACCESS_VIOLATION;
|
|
ExFreePool( buffer1 );
|
|
goto exit_with_lock;
|
|
}
|
|
|
|
Irp->AssociatedIrp.SystemBuffer = systemBuffer;
|
|
|
|
break;
|
|
}
|
|
|
|
case FSCTL_SRV_CHANGE_DOMAIN_NAME:
|
|
{
|
|
ULONG srpLength;
|
|
PSERVER_REQUEST_PACKET srp;
|
|
PSHARE share;
|
|
PLIST_ENTRY listEntry;
|
|
PENDPOINT endpoint;
|
|
|
|
if ( !SrvFspActive || SrvFspTransitioning ) {
|
|
status = STATUS_SUCCESS;
|
|
goto exit_with_lock;
|
|
}
|
|
|
|
srp = Irp->AssociatedIrp.SystemBuffer;
|
|
srpLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
|
|
|
|
//
|
|
// Make sure that the buffer was large enough to be a SRP.
|
|
//
|
|
|
|
if ( srpLength < sizeof(SERVER_REQUEST_PACKET) ||
|
|
srp->Name1.Length == 0) {
|
|
|
|
status = STATUS_INVALID_PARAMETER;
|
|
goto exit_with_lock;
|
|
}
|
|
|
|
//
|
|
// Adjust the buffer pointer to the srp address
|
|
//
|
|
(UINT_PTR) (srp->Name1.Buffer) += (UINT_PTR) srp;
|
|
(UINT_PTR) (srp->Name2.Buffer) += (UINT_PTR) srp;
|
|
|
|
if( (PCHAR) (srp->Name1.Buffer) < (PCHAR) srp ||
|
|
srp->Name1.Length > srpLength ||
|
|
(PCHAR) (srp->Name1.Buffer) > (PCHAR)srp + srpLength - srp->Name1.Length ||
|
|
(((UINT_PTR)(srp->Name1.Buffer) & ((sizeof(WCHAR)) - 1)) != 0) ) {
|
|
|
|
status = STATUS_ACCESS_VIOLATION;
|
|
goto exit_with_lock;
|
|
}
|
|
|
|
if( (PCHAR) (srp->Name2.Buffer) < (PCHAR) srp ||
|
|
srp->Name2.Length > srpLength ||
|
|
(PCHAR) (srp->Name2.Buffer) > (PCHAR)srp + srpLength - srp->Name2.Length ||
|
|
(((UINT_PTR)(srp->Name2.Buffer) & ((sizeof(WCHAR)) - 1)) != 0) ) {
|
|
|
|
status = STATUS_ACCESS_VIOLATION;
|
|
goto exit_with_lock;
|
|
}
|
|
|
|
//
|
|
// Run the endpoints and change the domain name for any endpoint having
|
|
// the original domain name. Note that the endpoint's domain name string buffers
|
|
// have already been allocated to the largest possible domain name.
|
|
//
|
|
ACQUIRE_LOCK( &SrvEndpointLock );
|
|
|
|
for( listEntry = SrvEndpointList.ListHead.Flink;
|
|
listEntry != &SrvEndpointList.ListHead;
|
|
listEntry = listEntry->Flink
|
|
) {
|
|
|
|
endpoint = CONTAINING_RECORD(
|
|
listEntry,
|
|
ENDPOINT,
|
|
GlobalEndpointListEntry
|
|
);
|
|
|
|
if( GET_BLOCK_STATE(endpoint) == BlockStateActive ) {
|
|
|
|
if( RtlEqualUnicodeString( &srp->Name1, &endpoint->DomainName, TRUE ) ) {
|
|
|
|
//
|
|
// Update the UNICODE domain name string
|
|
//
|
|
RtlCopyUnicodeString( &endpoint->DomainName, &srp->Name2 );
|
|
|
|
//
|
|
// Update the Oem domain name string
|
|
//
|
|
endpoint->OemDomainName.Length =
|
|
(SHORT)RtlUnicodeStringToOemSize( &endpoint->DomainName );
|
|
|
|
ASSERT( endpoint->OemDomainName.Length <=
|
|
endpoint->OemDomainName.MaximumLength );
|
|
|
|
RtlUnicodeStringToOemString(
|
|
&endpoint->OemDomainName,
|
|
&endpoint->DomainName,
|
|
FALSE // no allocate
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
RELEASE_LOCK( &SrvEndpointLock );
|
|
|
|
break;
|
|
}
|
|
|
|
case FSCTL_SRV_CHANGE_DNS_DOMAIN_NAME:
|
|
{
|
|
ULONG srpLength;
|
|
PSERVER_REQUEST_PACKET srp;
|
|
PSHARE share;
|
|
PLIST_ENTRY listEntry;
|
|
PENDPOINT endpoint;
|
|
PUNICODE_STRING pStr;
|
|
|
|
if ( !SrvFspActive || SrvFspTransitioning ) {
|
|
status = STATUS_SUCCESS;
|
|
goto exit_with_lock;
|
|
}
|
|
|
|
srp = Irp->AssociatedIrp.SystemBuffer;
|
|
srpLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
|
|
|
|
//
|
|
// Make sure that the buffer was large enough to be a SRP.
|
|
//
|
|
|
|
if ( srpLength < sizeof(SERVER_REQUEST_PACKET) ||
|
|
srp->Name1.Length == 0) {
|
|
|
|
status = STATUS_INVALID_PARAMETER;
|
|
goto exit_with_lock;
|
|
}
|
|
|
|
//
|
|
// Adjust the buffer pointer to the srp address
|
|
//
|
|
(UINT_PTR) (srp->Name1.Buffer) += (UINT_PTR) srp;
|
|
(UINT_PTR) (srp->Name2.Buffer) += (UINT_PTR) srp;
|
|
|
|
if( (PCHAR) (srp->Name1.Buffer) < (PCHAR) srp ||
|
|
srp->Name1.Length > srpLength ||
|
|
(PCHAR) (srp->Name1.Buffer) > (PCHAR)srp + srpLength - srp->Name1.Length ||
|
|
(((UINT_PTR)(srp->Name1.Buffer) & ((sizeof(WCHAR)) - 1)) != 0) ) {
|
|
|
|
status = STATUS_ACCESS_VIOLATION;
|
|
goto exit_with_lock;
|
|
}
|
|
|
|
if( (PCHAR) (srp->Name2.Buffer) < (PCHAR) srp ||
|
|
srp->Name2.Length > srpLength ||
|
|
(PCHAR) (srp->Name2.Buffer) > (PCHAR)srp + srpLength - srp->Name2.Length ||
|
|
(((UINT_PTR)(srp->Name2.Buffer) & ((sizeof(WCHAR)) - 1)) != 0) ) {
|
|
|
|
status = STATUS_ACCESS_VIOLATION;
|
|
goto exit_with_lock;
|
|
}
|
|
|
|
if( RtlEqualUnicodeString( &srp->Name1, &srp->Name2, TRUE ) )
|
|
{
|
|
// The DNS name is equal to the Netbios name, so avoid the check
|
|
ACQUIRE_LOCK( &SrvEndpointLock );
|
|
|
|
if( SrvDnsDomainName )
|
|
{
|
|
DEALLOCATE_NONPAGED_POOL( SrvDnsDomainName );
|
|
SrvDnsDomainName = NULL;
|
|
}
|
|
|
|
RELEASE_LOCK( &SrvEndpointLock );
|
|
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Change the DNS domain name
|
|
//
|
|
pStr = (PUNICODE_STRING)ALLOCATE_NONPAGED_POOL( sizeof(UNICODE_STRING) + srp->Name2.Length, BlockTypeMisc );
|
|
if( !pStr )
|
|
{
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto exit_with_lock;
|
|
}
|
|
|
|
pStr->MaximumLength = pStr->Length = srp->Name2.Length;
|
|
pStr->Buffer = (PWSTR)(pStr+1);
|
|
RtlCopyMemory( pStr->Buffer, srp->Name2.Buffer, srp->Name2.Length );
|
|
|
|
ACQUIRE_LOCK( &SrvEndpointLock );
|
|
|
|
if( SrvDnsDomainName )
|
|
{
|
|
DEALLOCATE_NONPAGED_POOL( SrvDnsDomainName );
|
|
}
|
|
|
|
SrvDnsDomainName = pStr;
|
|
|
|
RELEASE_LOCK( &SrvEndpointLock );
|
|
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case FSCTL_SRV_GET_QUEUE_STATISTICS:
|
|
{
|
|
PSRV_QUEUE_STATISTICS qstats;
|
|
SRV_QUEUE_STATISTICS tmpqstats;
|
|
PWORK_QUEUE queue;
|
|
LONG timeIncrement = (LONG)KeQueryTimeIncrement();
|
|
|
|
//
|
|
// Make sure the server is active.
|
|
//
|
|
if ( !SrvFspActive || SrvFspTransitioning ) {
|
|
|
|
status = STATUS_SERVER_NOT_STARTED;
|
|
goto exit_with_lock;
|
|
}
|
|
|
|
if ( IrpSp->Parameters.FileSystemControl.OutputBufferLength <
|
|
(SrvNumberOfProcessors+1) * sizeof( *qstats ) ) {
|
|
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
goto exit_with_lock;
|
|
}
|
|
|
|
qstats = Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
//
|
|
// Get the data for the normal processor queues
|
|
//
|
|
for( queue = SrvWorkQueues; queue < eSrvWorkQueues; queue++, qstats++ ) {
|
|
|
|
tmpqstats.QueueLength = KeReadStateQueue( &queue->Queue );
|
|
tmpqstats.ActiveThreads = queue->Threads - queue->AvailableThreads;
|
|
tmpqstats.AvailableThreads = queue->Threads;
|
|
tmpqstats.FreeWorkItems = queue->FreeWorkItems; // no lock!
|
|
tmpqstats.StolenWorkItems = queue->StolenWorkItems; // no lock!
|
|
tmpqstats.NeedWorkItem = queue->NeedWorkItem;
|
|
tmpqstats.CurrentClients = queue->CurrentClients;
|
|
|
|
tmpqstats.BytesReceived.QuadPart = queue->stats.BytesReceived;
|
|
tmpqstats.BytesSent.QuadPart = queue->stats.BytesSent;
|
|
tmpqstats.ReadOperations.QuadPart = queue->stats.ReadOperations;
|
|
tmpqstats.BytesRead.QuadPart = queue->stats.BytesRead;
|
|
tmpqstats.WriteOperations.QuadPart = queue->stats.WriteOperations;
|
|
tmpqstats.BytesWritten.QuadPart = queue->stats.BytesWritten;
|
|
tmpqstats.TotalWorkContextBlocksQueued = queue->stats.WorkItemsQueued;
|
|
tmpqstats.TotalWorkContextBlocksQueued.Count *= STATISTICS_SMB_INTERVAL;
|
|
tmpqstats.TotalWorkContextBlocksQueued.Time.QuadPart *= timeIncrement;
|
|
|
|
RtlCopyMemory( qstats, &tmpqstats, sizeof(tmpqstats) );
|
|
}
|
|
|
|
//
|
|
// Get the data for the blocking work queue
|
|
//
|
|
|
|
RtlZeroMemory( &tmpqstats, sizeof(tmpqstats) );
|
|
|
|
for( queue = SrvBlockingWorkQueues; queue < eSrvBlockingWorkQueues; queue++ )
|
|
{
|
|
tmpqstats.QueueLength += KeReadStateQueue( &queue->Queue );
|
|
tmpqstats.ActiveThreads += queue->Threads - queue->AvailableThreads;
|
|
tmpqstats.AvailableThreads += queue->AvailableThreads;
|
|
tmpqstats.BytesReceived.QuadPart += queue->stats.BytesReceived;
|
|
tmpqstats.BytesSent.QuadPart += queue->stats.BytesSent;
|
|
tmpqstats.ReadOperations.QuadPart += queue->stats.ReadOperations;
|
|
tmpqstats.BytesRead.QuadPart += queue->stats.BytesRead;
|
|
tmpqstats.WriteOperations.QuadPart += queue->stats.WriteOperations;
|
|
tmpqstats.BytesWritten.QuadPart += queue->stats.BytesWritten;
|
|
tmpqstats.TotalWorkContextBlocksQueued.Count += queue->stats.WorkItemsQueued.Count;
|
|
tmpqstats.TotalWorkContextBlocksQueued.Time.QuadPart += queue->stats.WorkItemsQueued.Time.QuadPart;
|
|
}
|
|
|
|
tmpqstats.TotalWorkContextBlocksQueued.Count *= STATISTICS_SMB_INTERVAL;
|
|
tmpqstats.TotalWorkContextBlocksQueued.Time.QuadPart *= timeIncrement;
|
|
|
|
RtlCopyMemory( qstats, &tmpqstats, sizeof(tmpqstats) );
|
|
|
|
Irp->IoStatus.Information = (SrvNumberOfProcessors + 1) * sizeof( *qstats );
|
|
|
|
status = STATUS_SUCCESS;
|
|
goto exit_with_lock;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case FSCTL_SRV_GET_STATISTICS:
|
|
|
|
//
|
|
// Make sure that the server is active.
|
|
//
|
|
|
|
if ( !SrvFspActive || SrvFspTransitioning ) {
|
|
//IF_DEBUG(ERRORS) {
|
|
// SrvPrint0( "LAN Manager server FSP not started.\n" );
|
|
//}
|
|
|
|
status = STATUS_SERVER_NOT_STARTED;
|
|
goto exit_with_lock;
|
|
}
|
|
|
|
{
|
|
SRV_STATISTICS tmpStatistics;
|
|
ULONG size;
|
|
|
|
//
|
|
// Make sure that the user buffer is large enough to hold some of the
|
|
// statistics database.
|
|
//
|
|
|
|
size = MIN( IrpSp->Parameters.FileSystemControl.OutputBufferLength,
|
|
sizeof( tmpStatistics ) );
|
|
|
|
if ( size == 0 ) {
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
goto exit_with_lock;
|
|
}
|
|
|
|
//
|
|
// Copy the statistics database to the user buffer. Store
|
|
// the statistics in a temporary buffer so we can convert
|
|
// the tick count stored to system time.
|
|
//
|
|
|
|
SrvUpdateStatisticsFromQueues( &tmpStatistics );
|
|
|
|
tmpStatistics.TotalWorkContextBlocksQueued.Time.QuadPart *=
|
|
(LONG)KeQueryTimeIncrement();
|
|
|
|
RtlCopyMemory(
|
|
Irp->AssociatedIrp.SystemBuffer,
|
|
&tmpStatistics,
|
|
size
|
|
);
|
|
|
|
Irp->IoStatus.Information = size;
|
|
|
|
}
|
|
|
|
status = STATUS_SUCCESS;
|
|
goto exit_with_lock;
|
|
|
|
#if SRVDBG_STATS || SRVDBG_STATS2
|
|
case FSCTL_SRV_GET_DEBUG_STATISTICS:
|
|
|
|
//
|
|
// Make sure that the server is active.
|
|
//
|
|
|
|
if ( !SrvFspActive || SrvFspTransitioning ) {
|
|
//IF_DEBUG(ERRORS) {
|
|
// SrvPrint0( "LAN Manager server FSP not started.\n" );
|
|
//}
|
|
|
|
status = STATUS_SERVER_NOT_STARTED;
|
|
goto exit_with_lock;
|
|
}
|
|
|
|
{
|
|
PSRV_STATISTICS_DEBUG stats;
|
|
|
|
//
|
|
// Make sure that the user buffer is large enough to hold the
|
|
// statistics database.
|
|
//
|
|
|
|
if ( IrpSp->Parameters.FileSystemControl.OutputBufferLength <
|
|
FIELD_OFFSET(SRV_STATISTICS_DEBUG,QueueStatistics) ) {
|
|
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
goto exit_with_lock;
|
|
}
|
|
|
|
//
|
|
// Acquire the statistics lock, then copy the statistics database
|
|
// to the user buffer.
|
|
//
|
|
|
|
stats = (PSRV_STATISTICS_DEBUG)Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
RtlCopyMemory(
|
|
stats,
|
|
&SrvDbgStatistics,
|
|
FIELD_OFFSET(SRV_STATISTICS_DEBUG,QueueStatistics) );
|
|
|
|
Irp->IoStatus.Information =
|
|
FIELD_OFFSET(SRV_STATISTICS_DEBUG,QueueStatistics);
|
|
|
|
if ( IrpSp->Parameters.FileSystemControl.OutputBufferLength >=
|
|
sizeof(SrvDbgStatistics) ) {
|
|
PWORK_QUEUE queue;
|
|
ULONG i, j;
|
|
i = 0;
|
|
stats->QueueStatistics[i].Depth = 0;
|
|
stats->QueueStatistics[i].Threads = 0;
|
|
#if SRVDBG_STATS2
|
|
stats->QueueStatistics[i].ItemsQueued = 0;
|
|
stats->QueueStatistics[i].MaximumDepth = 0;
|
|
#endif
|
|
for( queue = SrvWorkQueues; queue < eSrvWorkQueues; queue++ ) {
|
|
stats->QueueStatistics[i].Depth += KeReadStateQueue( &queue->Queue );
|
|
stats->QueueStatistics[i].Threads += queue->Threads;
|
|
#if SRVDBG_STATS2
|
|
stats->QueueStatistics[i].ItemsQueued += queue->ItemsQueued;
|
|
stats->QueueStatistics[i].MaximumDepth += queue->MaximumDepth + 1;
|
|
#endif
|
|
}
|
|
Irp->IoStatus.Information = sizeof(SrvDbgStatistics);
|
|
}
|
|
|
|
}
|
|
|
|
status = STATUS_SUCCESS;
|
|
goto exit_with_lock;
|
|
#endif // SRVDBG_STATS || SRVDBG_STATS2
|
|
//
|
|
// The follwing APIs must be processed in the server FSP because
|
|
// they open or close handles.
|
|
//
|
|
|
|
case FSCTL_SRV_NET_FILE_CLOSE:
|
|
case FSCTL_SRV_NET_SERVER_XPORT_ADD:
|
|
case FSCTL_SRV_NET_SERVER_XPORT_DEL:
|
|
case FSCTL_SRV_NET_SESSION_DEL:
|
|
case FSCTL_SRV_NET_SHARE_ADD:
|
|
case FSCTL_SRV_NET_SHARE_DEL:
|
|
|
|
{
|
|
PSERVER_REQUEST_PACKET srp;
|
|
PVOID buffer1;
|
|
PVOID buffer2;
|
|
PVOID systemBuffer;
|
|
ULONG buffer1Length;
|
|
ULONG buffer2Length;
|
|
ULONG systemBufferLength;
|
|
|
|
//
|
|
// Get the server request packet pointer.
|
|
//
|
|
|
|
srp = IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
|
|
|
|
//
|
|
// If the server is not running, or if it is in the process
|
|
// of shutting down, reject this request.
|
|
//
|
|
|
|
if ( !SrvFspActive || SrvFspTransitioning ) {
|
|
//IF_DEBUG(ERRORS) {
|
|
// SrvPrint0( "LAN Manager server FSP not started.\n" );
|
|
//}
|
|
|
|
srp->ErrorCode = NERR_ServerNotStarted;
|
|
status = STATUS_SUCCESS;
|
|
goto exit_with_lock;
|
|
}
|
|
|
|
//
|
|
// Determine the input buffer lengths, and make sure that the
|
|
// first buffer is large enough to be an SRP.
|
|
//
|
|
|
|
buffer1Length = IrpSp->Parameters.FileSystemControl.InputBufferLength;
|
|
buffer2Length = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
|
|
|
|
if ( buffer1Length < sizeof(SERVER_REQUEST_PACKET) ) {
|
|
status = STATUS_INVALID_PARAMETER;
|
|
goto exit_with_lock;
|
|
}
|
|
|
|
//
|
|
// Make the first buffer size is properly aligned so that the second
|
|
// buffer will be aligned as well.
|
|
//
|
|
|
|
buffer1Length = ALIGN_UP( buffer1Length, PVOID );
|
|
|
|
//
|
|
// Allocate a single buffer that will hold both input buffers.
|
|
// Note that the SRP part of the first buffer is copied back
|
|
// to the user as an output buffer.
|
|
//
|
|
|
|
systemBufferLength = buffer1Length + buffer2Length;
|
|
|
|
if( buffer1Length > SrvMaxFsctlBufferSize ||
|
|
buffer2Length > SrvMaxFsctlBufferSize ) {
|
|
|
|
status = STATUS_INVALID_PARAMETER;
|
|
goto exit_with_lock;
|
|
|
|
}
|
|
|
|
systemBuffer = ExAllocatePoolWithTagPriority( PagedPool, systemBufferLength, TAG_FROM_TYPE(BlockTypeMisc), LowPoolPriority );
|
|
|
|
if ( systemBuffer == NULL ) {
|
|
status = STATUS_INSUFF_SERVER_RESOURCES;
|
|
goto exit_with_lock;
|
|
}
|
|
|
|
buffer1 = systemBuffer;
|
|
buffer2 = (PCHAR)systemBuffer + buffer1Length;
|
|
|
|
//
|
|
// Copy the information into the buffers.
|
|
//
|
|
|
|
try {
|
|
RtlCopyMemory(
|
|
buffer1,
|
|
srp,
|
|
IrpSp->Parameters.FileSystemControl.InputBufferLength
|
|
);
|
|
if ( buffer2Length > 0 ) {
|
|
RtlCopyMemory( buffer2, Irp->UserBuffer, buffer2Length );
|
|
}
|
|
}
|
|
except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
status = STATUS_INVALID_PARAMETER;
|
|
ExFreePool( systemBuffer );
|
|
goto exit_with_lock;
|
|
}
|
|
|
|
//
|
|
// If a name was specified in the SRP, the buffer field will
|
|
// contain an offset rather than a pointer. Convert the offset
|
|
// to a pointer and verify that that it is a legal pointer.
|
|
//
|
|
|
|
srp = buffer1;
|
|
|
|
OFFSET_TO_POINTER( srp->Name1.Buffer, srp );
|
|
|
|
if ( !POINTER_IS_VALID( srp->Name1.Buffer, srp, buffer1Length ) ) {
|
|
status = STATUS_ACCESS_VIOLATION;
|
|
ExFreePool( buffer1 );
|
|
goto exit_with_lock;
|
|
}
|
|
|
|
OFFSET_TO_POINTER( srp->Name2.Buffer, srp );
|
|
|
|
if ( !POINTER_IS_VALID( srp->Name2.Buffer, srp, buffer1Length ) ) {
|
|
status = STATUS_ACCESS_VIOLATION;
|
|
ExFreePool( buffer1 );
|
|
goto exit_with_lock;
|
|
}
|
|
//
|
|
// Set up pointers in the IRP. The system buffer points to the
|
|
// buffer we just allocated to contain the input buffers. User
|
|
// buffer points to the SRP from the server service. This
|
|
// allows the SRP to be used as an output buffer-- the number of
|
|
// bytes specified by the Information field of the IO status
|
|
// block are copied from the system buffer to the user buffer at
|
|
// IO completion.
|
|
//
|
|
|
|
Irp->AssociatedIrp.SystemBuffer = systemBuffer;
|
|
Irp->UserBuffer = IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
|
|
|
|
//
|
|
// Set up other fields in the IRP so that the SRP is copied from
|
|
// the system buffer to the user buffer, and the system buffer
|
|
// is deallocated by IO completion.
|
|
//
|
|
|
|
Irp->Flags |= IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER |
|
|
IRP_INPUT_OPERATION;
|
|
Irp->IoStatus.Information = sizeof(SERVER_REQUEST_PACKET);
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// The following APIs should be processed in the server FSP because
|
|
// they reference and dereference structures, which could lead to
|
|
// handles being closed. However, it was too hard to change this
|
|
// (because of the need to return a separate SRP and data buffer) at
|
|
// the time this was realized (just before Product 1 shipment), so
|
|
// they are processed in the FSD, and all calls to NtClose attach to
|
|
// the server process first if necessary.
|
|
//
|
|
|
|
case FSCTL_SRV_NET_CONNECTION_ENUM:
|
|
case FSCTL_SRV_NET_FILE_ENUM:
|
|
case FSCTL_SRV_NET_SERVER_DISK_ENUM:
|
|
case FSCTL_SRV_NET_SERVER_XPORT_ENUM:
|
|
case FSCTL_SRV_NET_SESSION_ENUM:
|
|
case FSCTL_SRV_NET_SHARE_ENUM:
|
|
|
|
//
|
|
// These APIs are processed here in the server FSD.
|
|
//
|
|
|
|
case FSCTL_SRV_NET_SERVER_SET_INFO:
|
|
case FSCTL_SRV_NET_SHARE_SET_INFO:
|
|
case FSCTL_SRV_NET_STATISTICS_GET:
|
|
{
|
|
PSERVER_REQUEST_PACKET srp;
|
|
ULONG buffer1Length, buffer2Length;
|
|
PBYTE inputBuffer = NULL, outputBuffer = NULL;
|
|
PMDL OutputMdl = NULL;
|
|
BOOLEAN OutputLocked = FALSE;
|
|
|
|
//
|
|
// Get the server request packet pointer.
|
|
//
|
|
srp = IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
|
|
|
|
//
|
|
// If the server is not running, or if it is in the process
|
|
// of shutting down, reject this request.
|
|
//
|
|
|
|
if ( !SrvFspActive || SrvFspTransitioning ) {
|
|
|
|
try {
|
|
srp->ErrorCode = NERR_ServerNotStarted;
|
|
status = STATUS_SUCCESS;
|
|
|
|
}
|
|
except( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
goto exit_with_lock;
|
|
}
|
|
|
|
buffer1Length = IrpSp->Parameters.FileSystemControl.InputBufferLength;
|
|
buffer2Length = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
|
|
|
|
//
|
|
// Make sure that the buffer was large enough to be an SRP.
|
|
//
|
|
|
|
if ( buffer1Length < sizeof(SERVER_REQUEST_PACKET) ) {
|
|
status = STATUS_INVALID_PARAMETER;
|
|
goto exit_with_lock;
|
|
}
|
|
|
|
//
|
|
// Copy out the SRP. THis is to make sure they can't change that buffer while we're accessing it, since we
|
|
// place a pointer in there.
|
|
//
|
|
inputBuffer = ExAllocatePoolWithTagPriority( PagedPool, buffer1Length, TAG_FROM_TYPE(BlockTypeMisc), LowPoolPriority );
|
|
if( inputBuffer == NULL )
|
|
{
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto exit_with_lock;
|
|
}
|
|
|
|
//
|
|
// Try to copy the input memory into our own buffer
|
|
//
|
|
try {
|
|
|
|
RtlCopyMemory( inputBuffer, srp, buffer1Length );
|
|
srp = (SERVER_REQUEST_PACKET*)inputBuffer;
|
|
}
|
|
except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
ExFreePool(inputBuffer);
|
|
goto exit_with_lock;
|
|
}
|
|
|
|
//
|
|
// Increment the count of API requests in the server FSD.
|
|
//
|
|
|
|
SrvApiRequestCount++;
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
|
|
//
|
|
// If the output buffer length is 0, do not allocate an MDL,
|
|
// just go through the rest of the code so that the required buffer length
|
|
// and error are returned properly
|
|
//
|
|
if ( buffer2Length <= 0 ) {
|
|
OutputMdl = NULL;
|
|
outputBuffer = Irp->UserBuffer;
|
|
}
|
|
else {
|
|
OutputMdl = IoAllocateMdl( Irp->UserBuffer, buffer2Length, FALSE, TRUE, NULL );
|
|
|
|
// Try to lock down the pages
|
|
try {
|
|
MmProbeAndLockPages( OutputMdl, Irp->RequestorMode, IoWriteAccess );
|
|
OutputLocked = TRUE;
|
|
}
|
|
except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
// Catch the faults
|
|
status = GetExceptionCode();
|
|
goto finish_api_dispatch;
|
|
}
|
|
|
|
outputBuffer = MmGetMdlVirtualAddress( OutputMdl );
|
|
}
|
|
|
|
// Perform the operation
|
|
|
|
//
|
|
// If a name was specified in the SRP, the buffer field will
|
|
// contain an offset rather than a pointer. Convert the offset
|
|
// to a pointer and verify that that it is a legal pointer.
|
|
//
|
|
|
|
OFFSET_TO_POINTER( srp->Name1.Buffer, srp );
|
|
|
|
if ( !POINTER_IS_VALID( srp->Name1.Buffer, srp, buffer1Length ) ) {
|
|
status = STATUS_ACCESS_VIOLATION;
|
|
goto finish_api_dispatch;
|
|
}
|
|
|
|
OFFSET_TO_POINTER( srp->Name2.Buffer, srp );
|
|
|
|
if ( !POINTER_IS_VALID( srp->Name2.Buffer, srp, buffer1Length ) ) {
|
|
status = STATUS_ACCESS_VIOLATION;
|
|
goto finish_api_dispatch;
|
|
}
|
|
|
|
//
|
|
// We don't need the configuration lock any more.
|
|
//
|
|
|
|
RELEASE_LOCK( &SrvConfigurationLock );
|
|
|
|
//
|
|
// Dispatch the API request to the appripriate API processing
|
|
// routine. All these API requests are handled in the FSD.
|
|
//
|
|
|
|
status = SrvApiDispatchTable[ SRV_API_INDEX(code) ](
|
|
srp,
|
|
outputBuffer,
|
|
buffer2Length
|
|
);
|
|
|
|
//
|
|
// Decrement the count of outstanding API requests in the
|
|
// server. Hold the configuration lock while doing this, as it
|
|
// protects the API count variable.
|
|
//
|
|
|
|
ACQUIRE_LOCK( &SrvConfigurationLock );
|
|
SrvApiRequestCount--;
|
|
|
|
//
|
|
// Check to see whether the server is transitioning from started
|
|
// to not started. If so, and if this is the last API request
|
|
// to be completed, then set the API completion event which the
|
|
// shutdown code is waiting on.
|
|
//
|
|
// Since we checked SrvFspTransitioning at the start of the
|
|
// request, we know that the shutdown came after we started
|
|
// processing the API. If SrvApiRequestCount is 0, then there
|
|
// are no other threads in the FSD processing API requests.
|
|
// Therefore, it is safe for the shutdown code to proceed with
|
|
// the knowledge that no other thread in the server is
|
|
// operating.
|
|
//
|
|
|
|
if ( SrvFspTransitioning && SrvApiRequestCount == 0 ) {
|
|
KeSetEvent( &SrvApiCompletionEvent, 0, FALSE );
|
|
}
|
|
|
|
//
|
|
// Copy the SRP back into the buffer
|
|
//
|
|
try {
|
|
RtlCopyMemory( IrpSp->Parameters.FileSystemControl.Type3InputBuffer, srp, buffer1Length );
|
|
}
|
|
except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
status = GetExceptionCode();
|
|
}
|
|
|
|
|
|
|
|
finish_api_dispatch:
|
|
|
|
if( OutputLocked )
|
|
{
|
|
MmUnlockPages( OutputMdl );
|
|
}
|
|
|
|
if ( OutputMdl != NULL ) {
|
|
IoFreeMdl( OutputMdl );
|
|
OutputMdl = NULL;
|
|
}
|
|
|
|
if( inputBuffer )
|
|
{
|
|
ExFreePool( inputBuffer );
|
|
inputBuffer = NULL;
|
|
srp = NULL;
|
|
}
|
|
|
|
goto exit_with_lock;
|
|
}
|
|
|
|
case FSCTL_SRV_PAUSE:
|
|
|
|
//
|
|
// If the server is not running, or if it is in the process
|
|
// of shutting down, reject this request.
|
|
//
|
|
|
|
if ( !SrvFspActive || SrvFspTransitioning ) {
|
|
//IF_DEBUG(ERRORS) {
|
|
// SrvPrint0( "LAN Manager server FSP not started.\n" );
|
|
//}
|
|
|
|
status = STATUS_SERVER_NOT_STARTED;
|
|
goto exit_with_lock;
|
|
}
|
|
|
|
SrvPaused = TRUE;
|
|
|
|
status = STATUS_SUCCESS;
|
|
goto exit_with_lock;
|
|
|
|
case FSCTL_SRV_CONTINUE:
|
|
|
|
//
|
|
// If the server is not running, or if it is in the process
|
|
// of shutting down, reject this request.
|
|
//
|
|
|
|
if ( !SrvFspActive || SrvFspTransitioning ) {
|
|
//IF_DEBUG(ERRORS) {
|
|
// SrvPrint0( "LAN Manager server FSP not started.\n" );
|
|
//}
|
|
|
|
status = STATUS_SERVER_NOT_STARTED;
|
|
goto exit_with_lock;
|
|
}
|
|
|
|
SrvPaused = FALSE;
|
|
|
|
status = STATUS_SUCCESS;
|
|
goto exit_with_lock;
|
|
|
|
case FSCTL_SRV_GET_CHALLENGE:
|
|
{
|
|
PLIST_ENTRY sessionEntry;
|
|
PLUID inputLuid;
|
|
PSESSION session;
|
|
|
|
//
|
|
// If the server is not running, or if it is in the process
|
|
// of shutting down, reject this request.
|
|
//
|
|
|
|
if ( !SrvFspActive || SrvFspTransitioning ) {
|
|
//IF_DEBUG(ERRORS) {
|
|
// SrvPrint0( "LAN Manager server FSP not started.\n" );
|
|
//}
|
|
|
|
status = STATUS_SERVER_NOT_STARTED;
|
|
goto exit_with_lock;
|
|
}
|
|
|
|
if ( IrpSp->Parameters.FileSystemControl.InputBufferLength <
|
|
sizeof(LUID) ||
|
|
IrpSp->Parameters.FileSystemControl.OutputBufferLength <
|
|
sizeof(session->NtUserSessionKey) ) {
|
|
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
goto exit_with_lock;
|
|
}
|
|
|
|
RELEASE_LOCK( &SrvConfigurationLock );
|
|
|
|
inputLuid = (PLUID)Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
//
|
|
// Acquire the lock that protects the session list and walk the
|
|
// list looking for a user token that matches the one specified
|
|
// in the input buffer.
|
|
//
|
|
|
|
ACQUIRE_LOCK( SrvSessionList.Lock );
|
|
|
|
for ( sessionEntry = SrvSessionList.ListHead.Flink;
|
|
sessionEntry != &SrvSessionList.ListHead;
|
|
sessionEntry = sessionEntry->Flink ) {
|
|
|
|
session = CONTAINING_RECORD(
|
|
sessionEntry,
|
|
SESSION,
|
|
GlobalSessionListEntry
|
|
);
|
|
|
|
if ( RtlEqualLuid( inputLuid, &session->LogonId ) ) {
|
|
|
|
// Only give out the session key if its availible for giving out.
|
|
// This means that either:
|
|
// A) This key is not being used for signing or
|
|
// B) The key is being used for signing, and has either been encrypted or the other
|
|
// side doesn't support encryption
|
|
if( session->SessionKeyState == SrvSessionKeyAvailible )
|
|
{
|
|
//
|
|
// We found a match. Write the NT user session key into
|
|
// the output buffer.
|
|
//
|
|
|
|
RtlCopyMemory(
|
|
Irp->AssociatedIrp.SystemBuffer,
|
|
session->NtUserSessionKey,
|
|
sizeof(session->NtUserSessionKey)
|
|
);
|
|
|
|
RELEASE_LOCK( SrvSessionList.Lock );
|
|
|
|
Irp->IoStatus.Information = sizeof(session->NtUserSessionKey);
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
RELEASE_LOCK( SrvSessionList.Lock );
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
status = STATUS_ACCESS_DENIED;
|
|
}
|
|
|
|
goto exit_without_lock;
|
|
}
|
|
}
|
|
|
|
RELEASE_LOCK( SrvSessionList.Lock );
|
|
|
|
//
|
|
// There was no matching token in our session list. Fail the
|
|
// request.
|
|
//
|
|
|
|
status = STATUS_NO_TOKEN;
|
|
goto exit_without_lock;
|
|
}
|
|
|
|
case FSCTL_SRV_INTERNAL_TEST_REAUTH:
|
|
{
|
|
PSRV_REAUTH_TEST pReauthData;
|
|
ULONG BufferLength;
|
|
|
|
pReauthData = (PSRV_REAUTH_TEST)Irp->AssociatedIrp.SystemBuffer;
|
|
BufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
|
|
|
|
// Make sure the buffer size is good
|
|
if( BufferLength < sizeof(SRV_REAUTH_TEST) )
|
|
{
|
|
status = STATUS_INVALID_PARAMETER;
|
|
goto exit_with_lock;
|
|
}
|
|
|
|
// Pull out the parameters
|
|
SessionInvalidateCommand = pReauthData->InvalidateCommand;
|
|
SessionInvalidateMod = pReauthData->InvalidateModulo;
|
|
status = STATUS_SUCCESS;
|
|
goto exit_with_lock;
|
|
}
|
|
|
|
case FSCTL_DFS_RELEASE_SHARE_TABLE:
|
|
{
|
|
RELEASE_LOCK( &SrvConfigurationLock );
|
|
|
|
ACQUIRE_LOCK( &SrvShareLock );
|
|
|
|
status = SrvClearDfsOnShares();
|
|
|
|
RELEASE_LOCK( &SrvShareLock );
|
|
|
|
goto exit_without_lock;
|
|
}
|
|
|
|
case FSCTL_DFS_UPDATE_SHARE_TABLE:
|
|
{
|
|
PSHARE share;
|
|
PDFS_ATTACH_SHARE_BUFFER pBuffer = (PDFS_ATTACH_SHARE_BUFFER)Irp->AssociatedIrp.SystemBuffer;
|
|
UNICODE_STRING shareName;
|
|
ULONG BufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
|
|
|
|
RELEASE_LOCK( &SrvConfigurationLock );
|
|
|
|
if( (BufferLength < sizeof(DFS_ATTACH_SHARE_BUFFER)) ||
|
|
(BufferLength < sizeof(DFS_ATTACH_SHARE_BUFFER) + pBuffer->ShareNameLength - sizeof(WCHAR)) )
|
|
{
|
|
status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
else
|
|
{
|
|
shareName.Buffer = pBuffer->ShareName;
|
|
shareName.Length = shareName.MaximumLength = pBuffer->ShareNameLength;
|
|
|
|
ACQUIRE_LOCK( &SrvShareLock );
|
|
|
|
share = SrvFindShare( &shareName );
|
|
if( !share )
|
|
{
|
|
status = STATUS_OBJECT_NAME_NOT_FOUND;
|
|
}
|
|
else
|
|
{
|
|
share->IsDfsRoot = share->IsDfs = pBuffer->fAttach;
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
|
|
RELEASE_LOCK( &SrvShareLock );
|
|
}
|
|
|
|
goto exit_without_lock;
|
|
}
|
|
|
|
case FSCTL_SRV_QUERY_LWIO_CONTEXT:
|
|
{
|
|
ULONG BufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
|
|
PSRV_QUERY_RESUME_CONTEXT pBuffer = (PSRV_QUERY_RESUME_CONTEXT)Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
if (BufferLength < sizeof(SRV_QUERY_RESUME_CONTEXT)) {
|
|
status = STATUS_INVALID_PARAMETER;
|
|
} else if (BufferLength < SrvLWIOContextLength) {
|
|
pBuffer->ContextLength = SrvLWIOContextLength;
|
|
status = STATUS_BUFFER_OVERFLOW;
|
|
Irp->IoStatus.Information = sizeof(SRV_QUERY_RESUME_CONTEXT);
|
|
} else {
|
|
pBuffer->ContextLength = SrvLWIOContextLength;
|
|
RtlCopyMemory(pBuffer->Context, SrvLWIOContext, SrvLWIOContextLength);
|
|
status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Information = sizeof(SRV_QUERY_RESUME_CONTEXT) + SrvLWIOContextLength;
|
|
}
|
|
|
|
goto exit_with_lock;
|
|
}
|
|
|
|
case FSCTL_SRV_SET_LWIO_CONTEXT:
|
|
{
|
|
ULONG BufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
|
|
PSRV_SET_RESUME_CONTEXT pBuffer = (PSRV_SET_RESUME_CONTEXT)Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
if( (BufferLength < sizeof(SRV_SET_RESUME_CONTEXT)) ||
|
|
(BufferLength < FIELD_OFFSET( SRV_SET_RESUME_CONTEXT, Context ) + pBuffer->ContextLength) )
|
|
{
|
|
status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
else
|
|
{
|
|
// If a Callback is specified, caller must be kernel mode
|
|
if( (pBuffer->Callback != NULL) &&
|
|
(IoGetCurrentProcess() != SrvServerProcess) )
|
|
{
|
|
status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
else
|
|
{
|
|
if( SrvLWIOContext )
|
|
{
|
|
FREE_HEAP( SrvLWIOContext );
|
|
}
|
|
|
|
SrvLWIOContext = ALLOCATE_HEAP( pBuffer->ContextLength, BlockTypeMisc );
|
|
|
|
if( SrvLWIOContext ) {
|
|
RtlCopyMemory( SrvLWIOContext, pBuffer->Context, pBuffer->ContextLength );
|
|
SrvLWIOContextLength = pBuffer->ContextLength;
|
|
if (IoGetCurrentProcess() == SrvServerProcess)
|
|
SrvLWIOCallback = pBuffer->Callback;
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
}
|
|
}
|
|
|
|
goto exit_with_lock;
|
|
}
|
|
|
|
case FSCTL_SRV_REQUEST_HANDLE_DUP:
|
|
{
|
|
PSRV_REQUEST_HANDLE_DUP pDupRequest = (PSRV_REQUEST_HANDLE_DUP)Irp->AssociatedIrp.SystemBuffer;
|
|
ULONG InBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
|
|
ULONG OutBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
|
|
|
|
RELEASE_LOCK( &SrvConfigurationLock );
|
|
|
|
if( (InBufferLength < sizeof(SRV_REQUEST_HANDLE_DUP)) ||
|
|
(OutBufferLength < sizeof(SRV_RESPONSE_HANDLE_DUP)) )
|
|
{
|
|
status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
else
|
|
{
|
|
PSRV_RESPONSE_HANDLE_DUP pDupResponse = (PSRV_RESPONSE_HANDLE_DUP)(Irp->UserBuffer);
|
|
status = SrvProcessHandleDuplicateRequest( Irp, IrpSp, pDupRequest, pDupResponse );
|
|
}
|
|
|
|
goto exit_without_lock;
|
|
}
|
|
|
|
|
|
default:
|
|
|
|
INTERNAL_ERROR(
|
|
ERROR_LEVEL_EXPECTED,
|
|
"SrvFsdDispatchFsControl: Invalid I/O control "
|
|
"code received: %lx\n",
|
|
IrpSp->Parameters.FileSystemControl.FsControlCode,
|
|
NULL
|
|
);
|
|
status = STATUS_INVALID_PARAMETER;
|
|
goto exit_with_lock;
|
|
}
|
|
|
|
pWorkItem = IoAllocateWorkItem( SrvDeviceObject );
|
|
if( !pWorkItem )
|
|
{
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto exit_with_lock;
|
|
}
|
|
|
|
//
|
|
// Queue the request to the FSP for processing.
|
|
//
|
|
// *** Note that the request must be queued while the configuration
|
|
// lock is held in order to prevent an add/delete/etc request
|
|
// from checking the server state before a shutdown request, but
|
|
// being queued after that request.
|
|
//
|
|
|
|
IoMarkIrpPending( Irp );
|
|
|
|
QueueConfigurationIrp( Irp, pWorkItem );
|
|
|
|
RELEASE_LOCK( &SrvConfigurationLock );
|
|
|
|
FsRtlExitFileSystem();
|
|
|
|
return STATUS_PENDING;
|
|
|
|
exit_with_lock:
|
|
|
|
RELEASE_LOCK( &SrvConfigurationLock );
|
|
|
|
exit_without_lock:
|
|
|
|
FsRtlExitFileSystem();
|
|
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest( Irp, 2 );
|
|
|
|
return status;
|
|
|
|
} // SrvFsdDispatchFsControl
|
|
|
|
|
|
VOID
|
|
QueueConfigurationIrp (
|
|
IN PIRP Irp,
|
|
IN PIO_WORKITEM pWorkItem
|
|
)
|
|
{
|
|
PAGED_CODE( );
|
|
|
|
InterlockedIncrement( (PLONG)&SrvConfigurationIrpsInProgress );
|
|
|
|
SrvInsertTailList(
|
|
&SrvConfigurationWorkQueue,
|
|
&Irp->Tail.Overlay.ListEntry
|
|
);
|
|
|
|
|
|
IoQueueWorkItem( pWorkItem, SrvConfigurationThread, DelayedWorkQueue, (PVOID)pWorkItem );
|
|
|
|
} // QueueConfigurationIrp
|