1566 lines
44 KiB
C
1566 lines
44 KiB
C
/*++
|
||
|
||
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"
|
||
#pragma hdrstop
|
||
|
||
#define BugCheckFileId SRV_FILE_FSDDISP
|
||
|
||
#define CHANGE_HEURISTIC(heuristic) \
|
||
(newValues->HeuristicsChangeMask & SRV_HEUR_ ## heuristic) != 0
|
||
|
||
//
|
||
// Forward declarations
|
||
//
|
||
|
||
STATIC
|
||
NTSTATUS
|
||
SrvFsdDispatchFsControl (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PIO_STACK_LOCATION IrpSp
|
||
);
|
||
|
||
VOID
|
||
QueueConfigurationIrp (
|
||
IN PIRP Irp
|
||
);
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text( PAGE, SrvFsdDispatch )
|
||
#pragma alloc_text( PAGE, SrvFsdDispatchFsControl )
|
||
#pragma alloc_text( PAGE, QueueConfigurationIrp )
|
||
#endif
|
||
|
||
|
||
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;
|
||
|
||
PAGED_CODE( );
|
||
|
||
DeviceObject; // prevent compiler warnings
|
||
|
||
irpSp = IoGetCurrentIrpStackLocation( Irp );
|
||
|
||
switch ( irpSp->MajorFunction ) {
|
||
|
||
case IRP_MJ_CREATE:
|
||
|
||
ACQUIRE_LOCK( &SrvConfigurationLock );
|
||
|
||
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
|
||
//
|
||
RELEASE_LOCK( &SrvConfigurationLock );
|
||
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
|
||
//
|
||
RELEASE_LOCK( &SrvConfigurationLock );
|
||
status = STATUS_ACCESS_DENIED;
|
||
break;
|
||
}
|
||
|
||
SrvOpenCount++;
|
||
RELEASE_LOCK( &SrvConfigurationLock );
|
||
break;
|
||
|
||
case IRP_MJ_CLEANUP:
|
||
|
||
//
|
||
// Stop SmbTrace if the one closing is the client who started it.
|
||
//
|
||
|
||
SmbTraceStop( irpSp->FileObject, SMBTRACE_SERVER );
|
||
break;
|
||
|
||
case IRP_MJ_CLOSE:
|
||
|
||
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!
|
||
//
|
||
SrvXsActive = FALSE;
|
||
SrvFspTransitioning = TRUE;
|
||
IoMarkIrpPending( Irp );
|
||
QueueConfigurationIrp( Irp );
|
||
RELEASE_LOCK( &SrvConfigurationLock );
|
||
status = STATUS_PENDING;
|
||
goto exit;
|
||
}
|
||
}
|
||
RELEASE_LOCK( &SrvConfigurationLock );
|
||
break;
|
||
|
||
case IRP_MJ_FILE_SYSTEM_CONTROL:
|
||
|
||
status = SrvFsdDispatchFsControl( DeviceObject, Irp, irpSp );
|
||
goto exit;
|
||
|
||
case IRP_MJ_SHUTDOWN:
|
||
|
||
//
|
||
// Acquire the configuration lock.
|
||
//
|
||
|
||
ACQUIRE_LOCK( &SrvConfigurationLock );
|
||
|
||
//
|
||
// If the server is not running, or if it is in the process of
|
||
// shutting down, ignore this request.
|
||
//
|
||
|
||
if ( SrvFspActive && !SrvFspTransitioning ) {
|
||
|
||
SrvFspTransitioning = TRUE;
|
||
|
||
//
|
||
// 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 );
|
||
|
||
RELEASE_LOCK( &SrvConfigurationLock );
|
||
|
||
status = STATUS_PENDING;
|
||
goto exit;
|
||
|
||
}
|
||
|
||
RELEASE_LOCK( &SrvConfigurationLock );
|
||
|
||
break;
|
||
|
||
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;
|
||
|
||
DeviceObject; // prevent compiler warnings
|
||
|
||
//
|
||
// Initialize the I/O status block.
|
||
//
|
||
|
||
Irp->IoStatus.Status = STATUS_PENDING;
|
||
Irp->IoStatus.Information = 0;
|
||
|
||
//
|
||
// Acquire the configuration lock.
|
||
//
|
||
|
||
ACQUIRE_LOCK( &SrvConfigurationLock );
|
||
|
||
//
|
||
// Process the request if possible.
|
||
//
|
||
|
||
code = IrpSp->Parameters.FileSystemControl.FsControlCode;
|
||
|
||
switch ( code ) {
|
||
|
||
case FSCTL_SRV_STARTUP: {
|
||
|
||
PSERVER_REQUEST_PACKET srp;
|
||
ULONG srpLength;
|
||
PVOID inputBuffer;
|
||
ULONG inputBufferLength;
|
||
|
||
//
|
||
// 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" );
|
||
//}
|
||
|
||
srp->ErrorCode = NERR_ServiceInstalled;
|
||
status = STATUS_SUCCESS;
|
||
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;
|
||
}
|
||
|
||
//
|
||
// If a domain name was specified in the SRP, the buffer field
|
||
// contains 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, srpLength ) ) {
|
||
|
||
status = STATUS_ACCESS_VIOLATION;
|
||
goto exit_with_lock;
|
||
}
|
||
|
||
//
|
||
// If a server name was specified in the SRP, the buffer field
|
||
// contains 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->Name2.Buffer, srp );
|
||
|
||
if ( !POINTER_IS_VALID( srp->Name2.Buffer, srp, srpLength ) ) {
|
||
|
||
status = STATUS_ACCESS_VIOLATION;
|
||
goto exit_with_lock;
|
||
}
|
||
|
||
//
|
||
// Call SrvNetServerSetInfo to set the initial server configuration
|
||
// information.
|
||
//
|
||
|
||
status = SrvNetServerSetInfo(
|
||
srp,
|
||
inputBuffer,
|
||
inputBufferLength
|
||
);
|
||
|
||
//
|
||
// Indicate that the server is starting up. This prevents
|
||
// further startup requests from being issued.
|
||
//
|
||
|
||
SrvFspTransitioning = TRUE;
|
||
|
||
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;
|
||
|
||
//
|
||
// If SmbTrace is running, stop it.
|
||
//
|
||
|
||
SmbTraceStop( NULL, SMBTRACE_SERVER );
|
||
|
||
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 %X, Read %X, Close %x, DeRegister %x",
|
||
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 the first buffer size an even multiple of four so that
|
||
// the second buffer starts on a longword boundary.
|
||
//
|
||
|
||
buffer1Length = (buffer1Length + 3) & ~3;
|
||
|
||
//
|
||
// Allocate a single buffer that will hold both input buffers.
|
||
//
|
||
|
||
systemBufferLength = buffer1Length + buffer2Length;
|
||
systemBuffer = ExAllocatePool( PagedPool, systemBufferLength );
|
||
|
||
if ( systemBuffer == NULL ) {
|
||
status = STATUS_INSUFF_SERVER_RESOURCES;
|
||
goto exit_with_lock;
|
||
}
|
||
|
||
buffer1 = systemBuffer;
|
||
buffer2 = (PCHAR)systemBuffer + buffer1Length;
|
||
|
||
//
|
||
// Copy the information into the buffers.
|
||
//
|
||
|
||
RtlCopyMemory(
|
||
buffer1,
|
||
IrpSp->Parameters.FileSystemControl.Type3InputBuffer,
|
||
IrpSp->Parameters.FileSystemControl.InputBufferLength
|
||
);
|
||
if ( buffer2Length > 0 ) {
|
||
RtlCopyMemory( buffer2, Irp->UserBuffer, buffer2Length );
|
||
}
|
||
|
||
//
|
||
// 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_SHARE_STATE_CHANGE:
|
||
{
|
||
ULONG srpLength;
|
||
PSERVER_REQUEST_PACKET srp;
|
||
PSHARE share;
|
||
|
||
if ( !SrvFspActive || SrvFspTransitioning ) {
|
||
status = STATUS_SUCCESS;
|
||
goto exit_with_lock;
|
||
}
|
||
|
||
srp = Irp->AssociatedIrp.SystemBuffer;
|
||
srpLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
|
||
|
||
OFFSET_TO_POINTER( srp->Name1.Buffer, srp );
|
||
|
||
if (!POINTER_IS_VALID( srp->Name1.Buffer, srp, srpLength)) {
|
||
status = STATUS_ACCESS_VIOLATION;
|
||
goto exit_with_lock;
|
||
}
|
||
|
||
ACQUIRE_LOCK( &SrvShareLock );
|
||
|
||
share = SrvFindShare( &srp->Name1 );
|
||
|
||
if ( share != NULL) {
|
||
|
||
share->IsDfs = ((srp->Flags & SRP_SET_SHARE_IN_DFS) != 0);
|
||
|
||
status = STATUS_SUCCESS;
|
||
|
||
} else {
|
||
|
||
status = STATUS_OBJECT_NAME_NOT_FOUND;
|
||
|
||
}
|
||
|
||
RELEASE_LOCK( &SrvShareLock );
|
||
|
||
goto exit_with_lock;
|
||
|
||
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
|
||
//
|
||
|
||
tmpqstats.QueueLength = KeReadStateQueue( &SrvBlockingWorkQueue.Queue );
|
||
tmpqstats.ActiveThreads = SrvBlockingWorkQueue.Threads -
|
||
SrvBlockingWorkQueue.AvailableThreads;
|
||
tmpqstats.AvailableThreads = SrvBlockingWorkQueue.Threads;
|
||
tmpqstats.FreeWorkItems = SrvBlockingWorkQueue.FreeWorkItems; // no lock!
|
||
tmpqstats.StolenWorkItems = SrvBlockingWorkQueue.StolenWorkItems; // no lock!
|
||
tmpqstats.NeedWorkItem = SrvBlockingWorkQueue.NeedWorkItem;
|
||
tmpqstats.CurrentClients = SrvBlockingWorkQueue.CurrentClients;
|
||
|
||
tmpqstats.BytesReceived.QuadPart = SrvBlockingWorkQueue.stats.BytesReceived;
|
||
tmpqstats.BytesSent.QuadPart = SrvBlockingWorkQueue.stats.BytesSent;
|
||
tmpqstats.ReadOperations.QuadPart = SrvBlockingWorkQueue.stats.ReadOperations;
|
||
tmpqstats.BytesRead.QuadPart = SrvBlockingWorkQueue.stats.BytesRead;
|
||
tmpqstats.WriteOperations.QuadPart = SrvBlockingWorkQueue.stats.WriteOperations;
|
||
tmpqstats.BytesWritten.QuadPart = SrvBlockingWorkQueue.stats.BytesWritten;
|
||
|
||
tmpqstats.TotalWorkContextBlocksQueued
|
||
= SrvBlockingWorkQueue.stats.WorkItemsQueued;
|
||
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;
|
||
|
||
//
|
||
// Make sure that the user buffer is large enough to hold the
|
||
// statistics database.
|
||
//
|
||
|
||
if ( IrpSp->Parameters.FileSystemControl.OutputBufferLength <
|
||
sizeof(SRV_STATISTICS) ) {
|
||
|
||
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,
|
||
sizeof(tmpStatistics)
|
||
);
|
||
|
||
Irp->IoStatus.Information = sizeof(tmpStatistics);
|
||
|
||
}
|
||
|
||
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_CHARDEV_CONTROL:
|
||
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 an even multiple of four so that
|
||
// the second buffer starts on a longword boundary.
|
||
//
|
||
|
||
buffer1Length = (buffer1Length + 3) & ~3;
|
||
|
||
//
|
||
// 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;
|
||
systemBuffer = ExAllocatePool( PagedPool, systemBufferLength );
|
||
|
||
if ( systemBuffer == NULL ) {
|
||
status = STATUS_INSUFF_SERVER_RESOURCES;
|
||
goto exit_with_lock;
|
||
}
|
||
|
||
buffer1 = systemBuffer;
|
||
buffer2 = (PCHAR)systemBuffer + buffer1Length;
|
||
|
||
//
|
||
// Copy the information into the buffers.
|
||
//
|
||
|
||
RtlCopyMemory(
|
||
buffer1,
|
||
srp,
|
||
IrpSp->Parameters.FileSystemControl.InputBufferLength
|
||
);
|
||
if ( buffer2Length > 0 ) {
|
||
RtlCopyMemory( buffer2, Irp->UserBuffer, buffer2Length );
|
||
}
|
||
|
||
//
|
||
// 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_CHARDEV_ENUM:
|
||
case FSCTL_SRV_NET_CHARDEVQ_ENUM:
|
||
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_CHARDEVQ_PURGE:
|
||
case FSCTL_SRV_NET_CHARDEVQ_SET_INFO:
|
||
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;
|
||
|
||
//
|
||
// Get the server request packet pointer.
|
||
//
|
||
|
||
srp = IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
|
||
buffer1Length = IrpSp->Parameters.FileSystemControl.InputBufferLength;
|
||
|
||
//
|
||
// 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;
|
||
}
|
||
|
||
//
|
||
// Increment the count of API requests in the server FSD.
|
||
//
|
||
|
||
SrvApiRequestCount++;
|
||
|
||
//
|
||
// 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;
|
||
}
|
||
|
||
//
|
||
// 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 exit_with_lock;
|
||
}
|
||
|
||
OFFSET_TO_POINTER( srp->Name2.Buffer, srp );
|
||
|
||
if ( !POINTER_IS_VALID( srp->Name2.Buffer, srp, buffer1Length ) ) {
|
||
status = STATUS_ACCESS_VIOLATION;
|
||
goto exit_with_lock;
|
||
}
|
||
|
||
//
|
||
// 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,
|
||
Irp->UserBuffer,
|
||
IrpSp->Parameters.FileSystemControl.OutputBufferLength
|
||
);
|
||
|
||
//
|
||
// 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 );
|
||
}
|
||
|
||
goto exit_with_lock;
|
||
}
|
||
|
||
#ifdef OLDNET
|
||
case FSCTL_SRV_SET_DEBUG:
|
||
{
|
||
ULONG inputLength;
|
||
ULONG outputLength;
|
||
FSCTL_SRV_SET_DEBUG_IN_OUT oldValues;
|
||
|
||
extern ULONG CcDebugTraceLevel;
|
||
extern ULONG PbDebugTraceLevel;
|
||
extern ULONG FatDebugTraceLevel;
|
||
|
||
//
|
||
// Make sure that the input buffer is the right size.
|
||
//
|
||
|
||
inputLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
|
||
|
||
if ( (inputLength != 0) &&
|
||
(inputLength < sizeof(FSCTL_SRV_SET_DEBUG_IN_OUT)) ) {
|
||
status = STATUS_BUFFER_TOO_SMALL;
|
||
goto exit_with_lock;
|
||
}
|
||
|
||
outputLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
|
||
|
||
if ( outputLength != 0 ) {
|
||
|
||
//
|
||
// Make sure that the output buffer is the right size.
|
||
//
|
||
|
||
if ( outputLength < sizeof(FSCTL_SRV_SET_DEBUG_IN_OUT) ) {
|
||
status = STATUS_BUFFER_TOO_SMALL;
|
||
goto exit_with_lock;
|
||
}
|
||
|
||
//
|
||
// Save the old flags and heuristics in a local structure.
|
||
// (The input and output buffers coincide, so we can't copy
|
||
// the old values into the output buffer yet.)
|
||
//
|
||
|
||
oldValues.SrvDebugOff = 0xffffffff;
|
||
oldValues.SmbDebugOff = 0xffffffff;
|
||
#if SRVDBG
|
||
oldValues.SrvDebugOn = SrvDebug.QuadPart;
|
||
oldValues.SmbDebugOn = SmbDebug;
|
||
#else
|
||
oldValues.SrvDebugOn = 0;
|
||
oldValues.SmbDebugOn = 0;
|
||
#endif
|
||
oldValues.HeuristicsChangeMask = 0xffffffff;
|
||
oldValues.MaxCopyReadLength = SrvMaxCopyReadLength;
|
||
oldValues.MaxCopyWriteLength = SrvMaxCopyWriteLength;
|
||
oldValues.EnableOplocks = SrvEnableOplocks;
|
||
oldValues.EnableFcbOpens = SrvEnableFcbOpens;
|
||
oldValues.EnableSoftCompatibility = SrvEnableSoftCompatibility;
|
||
oldValues.EnableRawMode = SrvEnableRawMode;
|
||
|
||
oldValues.CcDebugOff = 0xffffffff;
|
||
#ifdef CCDBG
|
||
oldValues.CcDebugOn = CcDebugTraceLevel;
|
||
#else
|
||
oldValues.CcDebugOn = 0;
|
||
#endif
|
||
oldValues.PbDebugOff = 0xffffffff;
|
||
#ifdef PBDBG
|
||
oldValues.PbDebugOn = PbDebugTraceLevel;
|
||
#else
|
||
oldValues.PbDebugOn = 0;
|
||
#endif
|
||
oldValues.FatDebugOff = 0xffffffff;
|
||
#ifdef FATDBG
|
||
oldValues.FatDebugOn = FatDebugTraceLevel;
|
||
#else
|
||
oldValues.FatDebugOn = 0;
|
||
#endif
|
||
|
||
}
|
||
|
||
//
|
||
// If requested, change flags and heuristics as specified.
|
||
//
|
||
|
||
if ( inputLength != 0 ) {
|
||
|
||
PFSCTL_SRV_SET_DEBUG_IN_OUT newValues =
|
||
Irp->AssociatedIrp.SystemBuffer;
|
||
|
||
#if SRVDBG
|
||
SrvDebug &= ~newValues->SrvDebugOff;
|
||
SrvDebug |= newValues->SrvDebugOn;
|
||
SmbDebug &= ~newValues->SmbDebugOff;
|
||
SmbDebug |= newValues->SmbDebugOn;
|
||
#endif
|
||
|
||
if ( CHANGE_HEURISTIC(MAX_COPY_READ) ) {
|
||
SrvMaxCopyReadLength = newValues->MaxCopyReadLength;
|
||
}
|
||
if ( CHANGE_HEURISTIC(MAX_COPY_WRITE) ) {
|
||
SrvMaxCopyWriteLength = newValues->MaxCopyWriteLength;
|
||
}
|
||
|
||
if ( CHANGE_HEURISTIC(OPLOCKS) ) {
|
||
SrvEnableOplocks = newValues->EnableOplocks;
|
||
}
|
||
if ( CHANGE_HEURISTIC(FCB_OPENS) ) {
|
||
SrvEnableFcbOpens = newValues->EnableFcbOpens;
|
||
}
|
||
if ( CHANGE_HEURISTIC(SOFT_COMPATIBILITY) ) {
|
||
SrvEnableSoftCompatibility = newValues->EnableSoftCompatibility;
|
||
}
|
||
if ( CHANGE_HEURISTIC(RAW_MODE) ) {
|
||
SrvEnableRawMode = newValues->EnableRawMode;
|
||
}
|
||
|
||
#ifdef CCDBG
|
||
CcDebugTraceLevel &= ~newValues->CcDebugOff;
|
||
CcDebugTraceLevel |= newValues->CcDebugOn;
|
||
#endif
|
||
#ifdef PBDBG
|
||
PbDebugTraceLevel &= ~newValues->PbDebugOff;
|
||
PbDebugTraceLevel |= newValues->PbDebugOn;
|
||
#endif
|
||
#ifdef FATDBG
|
||
FatDebugTraceLevel &= ~newValues->FatDebugOff;
|
||
FatDebugTraceLevel |= newValues->FatDebugOn;
|
||
#endif
|
||
|
||
}
|
||
|
||
//
|
||
// If requested, copy the old values into the output buffer.
|
||
//
|
||
|
||
if ( outputLength != 0 ) {
|
||
|
||
RtlCopyMemory(
|
||
Irp->AssociatedIrp.SystemBuffer,
|
||
&oldValues,
|
||
sizeof(FSCTL_SRV_SET_DEBUG_IN_OUT)
|
||
);
|
||
|
||
Irp->IoStatus.Information = sizeof(FSCTL_SRV_SET_DEBUG_IN_OUT);
|
||
|
||
}
|
||
|
||
status = STATUS_SUCCESS;
|
||
goto exit_with_lock;
|
||
}
|
||
#endif // def OLDNET
|
||
|
||
case FSCTL_SRV_START_SMBTRACE:
|
||
|
||
if ( SmbTraceActive[SMBTRACE_SERVER] ) {
|
||
status = STATUS_SHARING_VIOLATION;
|
||
goto exit_with_lock;
|
||
}
|
||
|
||
if ( !SrvFspActive || SrvFspTransitioning ) {
|
||
status = STATUS_SERVER_NOT_STARTED;
|
||
goto exit_with_lock;
|
||
}
|
||
|
||
break; // FSP continues the processing.
|
||
|
||
case FSCTL_SRV_END_SMBTRACE:
|
||
|
||
//
|
||
// If the server is not running, or if it is in the process
|
||
// of shutting down, reject this request.
|
||
//
|
||
|
||
if ( !SrvFspActive || SrvFspTransitioning ) {
|
||
status = STATUS_SERVER_NOT_STARTED;
|
||
goto exit_with_lock;
|
||
}
|
||
|
||
//
|
||
// Attempt to stop SmbTrace. It will likely return
|
||
// STATUS_PENDING, indicating that it is in the process
|
||
// of shutting down. STATUS_PENDING is a poor value
|
||
// to return (according to an assertion in io\iosubs.c)
|
||
// so we convert it to success. Better would be for
|
||
// SmbTraceStop to wait until it has successfully stopped.
|
||
//
|
||
|
||
status = SmbTraceStop( NULL, SMBTRACE_SERVER );
|
||
|
||
//
|
||
// Complete the request with success.
|
||
//
|
||
|
||
status = STATUS_SUCCESS;
|
||
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 ) ) {
|
||
|
||
//
|
||
// 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;
|
||
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;
|
||
}
|
||
|
||
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;
|
||
}
|
||
|
||
//
|
||
// 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 );
|
||
|
||
RELEASE_LOCK( &SrvConfigurationLock );
|
||
|
||
return STATUS_PENDING;
|
||
|
||
exit_with_lock:
|
||
|
||
RELEASE_LOCK( &SrvConfigurationLock );
|
||
|
||
exit_without_lock:
|
||
|
||
Irp->IoStatus.Status = status;
|
||
IoCompleteRequest( Irp, 2 );
|
||
|
||
return status;
|
||
|
||
} // SrvFsdDispatchFsControl
|
||
|
||
|
||
VOID
|
||
QueueConfigurationIrp (
|
||
IN PIRP Irp
|
||
)
|
||
{
|
||
PWORK_QUEUE_ITEM p;
|
||
|
||
PAGED_CODE( );
|
||
|
||
InterlockedIncrement( (PLONG)&SrvConfigurationIrpsInProgress );
|
||
|
||
SrvInsertTailList(
|
||
&SrvConfigurationWorkQueue,
|
||
&Irp->Tail.Overlay.ListEntry
|
||
);
|
||
|
||
//
|
||
// Hunt for a SrvConfigurationThreadWorkItem we can use. If they
|
||
// are all occupied, this means that config threads are going to
|
||
// run and we don't need to worry about it.
|
||
//
|
||
|
||
for( p = SrvConfigurationThreadWorkItem;
|
||
p < &SrvConfigurationThreadWorkItem[ MAX_CONFIG_WORK_ITEMS ];
|
||
p++ ) {
|
||
|
||
if( p->Parameter == 0 ) {
|
||
p->Parameter = p;
|
||
ExQueueWorkItem( p, DelayedWorkQueue );
|
||
break;
|
||
}
|
||
|
||
}
|
||
|
||
} // QueueConfigurationIrp
|
||
|