3065 lines
76 KiB
C
3065 lines
76 KiB
C
/*++
|
||
|
||
Copyright (c) 1990 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
smbpipe.c
|
||
|
||
Abstract:
|
||
|
||
This module contains the code for handling named pipe based transact
|
||
SMB's.
|
||
|
||
Functions that are handled are:
|
||
SrvCallNamedPipe
|
||
SrvWaitNamedPipe
|
||
SrvQueryInfoNamedPipe
|
||
SrvQueryStateNamedPipe
|
||
SrvSetStateNamedPipe
|
||
SrvPeekNamedPipe
|
||
SrvTransactNamedPipe
|
||
|
||
Author:
|
||
|
||
Manny Weiser (9-18-90)
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "precomp.h"
|
||
#include "pipe.tmh"
|
||
#pragma hdrstop
|
||
|
||
#define BugCheckFileId SRV_FILE_PIPE
|
||
|
||
STATIC
|
||
VOID SRVFASTCALL
|
||
RestartCallNamedPipe (
|
||
IN OUT PWORK_CONTEXT WorkContext
|
||
);
|
||
|
||
STATIC
|
||
VOID SRVFASTCALL
|
||
RestartWaitNamedPipe (
|
||
IN OUT PWORK_CONTEXT WorkContext
|
||
);
|
||
|
||
STATIC
|
||
VOID SRVFASTCALL
|
||
RestartPeekNamedPipe (
|
||
IN OUT PWORK_CONTEXT WorkContext
|
||
);
|
||
|
||
VOID SRVFASTCALL
|
||
RestartRawWriteNamedPipe (
|
||
IN OUT PWORK_CONTEXT WorkContext
|
||
);
|
||
|
||
STATIC
|
||
VOID SRVFASTCALL
|
||
RestartTransactNamedPipe (
|
||
IN OUT PWORK_CONTEXT WorkContext
|
||
);
|
||
|
||
NTSTATUS
|
||
RestartFastTransactNamedPipe (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN OUT PWORK_CONTEXT WorkContext
|
||
);
|
||
|
||
VOID SRVFASTCALL
|
||
RestartFastTransactNamedPipe2 (
|
||
IN OUT PWORK_CONTEXT WorkContext
|
||
);
|
||
|
||
VOID SRVFASTCALL
|
||
RestartReadNamedPipe (
|
||
IN OUT PWORK_CONTEXT WorkContext
|
||
);
|
||
|
||
VOID SRVFASTCALL
|
||
RestartWriteNamedPipe (
|
||
IN OUT PWORK_CONTEXT WorkContext
|
||
);
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text( PAGE, SrvCallNamedPipe )
|
||
#pragma alloc_text( PAGE, SrvWaitNamedPipe )
|
||
#pragma alloc_text( PAGE, SrvQueryStateNamedPipe )
|
||
#pragma alloc_text( PAGE, SrvQueryInformationNamedPipe )
|
||
#pragma alloc_text( PAGE, SrvSetStateNamedPipe )
|
||
#pragma alloc_text( PAGE, SrvPeekNamedPipe )
|
||
#pragma alloc_text( PAGE, SrvTransactNamedPipe )
|
||
#pragma alloc_text( PAGE, SrvFastTransactNamedPipe )
|
||
#pragma alloc_text( PAGE, SrvRawWriteNamedPipe )
|
||
#pragma alloc_text( PAGE, SrvReadNamedPipe )
|
||
#pragma alloc_text( PAGE, SrvWriteNamedPipe )
|
||
#pragma alloc_text( PAGE, RestartCallNamedPipe )
|
||
#pragma alloc_text( PAGE, RestartWaitNamedPipe )
|
||
#pragma alloc_text( PAGE, RestartPeekNamedPipe )
|
||
#pragma alloc_text( PAGE, RestartReadNamedPipe )
|
||
#pragma alloc_text( PAGE, RestartTransactNamedPipe )
|
||
#pragma alloc_text( PAGE, RestartRawWriteNamedPipe )
|
||
#pragma alloc_text( PAGE, RestartFastTransactNamedPipe2 )
|
||
#pragma alloc_text( PAGE, RestartWriteNamedPipe )
|
||
#pragma alloc_text( PAGE8FIL, RestartFastTransactNamedPipe )
|
||
#endif
|
||
|
||
|
||
SMB_TRANS_STATUS
|
||
SrvCallNamedPipe (
|
||
IN OUT PWORK_CONTEXT WorkContext
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function processes a Call Named pipe request from a
|
||
Transaction SMB. This call is handled asynchronously and
|
||
is completed in RestartCallNamedPipe.
|
||
|
||
Arguments:
|
||
|
||
WorkContext - A pointer to a WORK_CONTEXT block.
|
||
|
||
Return Value:
|
||
|
||
SMB_TRANS_STATUS - Indicates whether an error occurred. See
|
||
smbtypes.h for a more complete description.
|
||
|
||
--*/
|
||
|
||
{
|
||
HANDLE fileHandle;
|
||
IO_STATUS_BLOCK ioStatusBlock;
|
||
OBJECT_ATTRIBUTES objectAttributes;
|
||
PFILE_OBJECT fileObject;
|
||
OBJECT_HANDLE_INFORMATION handleInformation;
|
||
PTRANSACTION transaction;
|
||
NTSTATUS status;
|
||
UNICODE_STRING pipePath;
|
||
UNICODE_STRING fullName;
|
||
FILE_PIPE_INFORMATION pipeInformation;
|
||
PIRP irp = WorkContext->Irp;
|
||
PIO_STACK_LOCATION irpSp;
|
||
|
||
PAGED_CODE( );
|
||
|
||
//
|
||
// Strip "\PIPE\" prefix from the path string.
|
||
//
|
||
|
||
pipePath = WorkContext->Parameters.Transaction->TransactionName;
|
||
|
||
if ( pipePath.Length <=
|
||
(UNICODE_SMB_PIPE_PREFIX_LENGTH + sizeof(WCHAR)) ) {
|
||
|
||
SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
|
||
return SmbTransStatusErrorWithoutData;
|
||
|
||
}
|
||
|
||
pipePath.Buffer +=
|
||
(UNICODE_SMB_PIPE_PREFIX_LENGTH / sizeof(WCHAR)) + 1;
|
||
pipePath.Length -= UNICODE_SMB_PIPE_PREFIX_LENGTH + sizeof(WCHAR);
|
||
|
||
//
|
||
// Attempt to open the named pipe.
|
||
//
|
||
|
||
SrvAllocateAndBuildPathName(
|
||
&SrvNamedPipeRootDirectory,
|
||
&pipePath,
|
||
NULL,
|
||
&fullName
|
||
);
|
||
|
||
if ( fullName.Buffer == NULL ) {
|
||
|
||
//
|
||
// Unable to allocate heap for the full name.
|
||
//
|
||
|
||
IF_DEBUG(ERRORS) {
|
||
SrvPrint0( "SrvCallNamedPipe: Unable to allocate heap for full path name\n" );
|
||
}
|
||
|
||
SrvSetSmbError (WorkContext, STATUS_INSUFF_SERVER_RESOURCES);
|
||
IF_DEBUG(TRACE2) SrvPrint0( "SrvCallNamedPipe complete\n" );
|
||
return SmbTransStatusErrorWithoutData;
|
||
}
|
||
|
||
SrvInitializeObjectAttributes_U(
|
||
&objectAttributes,
|
||
&fullName,
|
||
OBJ_CASE_INSENSITIVE,
|
||
NULL,
|
||
NULL
|
||
);
|
||
|
||
INCREMENT_DEBUG_STAT( SrvDbgStatistics.TotalOpenAttempts );
|
||
|
||
status = SrvIoCreateFile(
|
||
WorkContext,
|
||
&fileHandle,
|
||
GENERIC_READ | GENERIC_WRITE,
|
||
&objectAttributes,
|
||
&ioStatusBlock,
|
||
NULL,
|
||
FILE_ATTRIBUTE_NORMAL,
|
||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||
FILE_OPEN,
|
||
0, // Create Options
|
||
NULL, // EA Buffer
|
||
0, // EA Length
|
||
CreateFileTypeNone,
|
||
(PVOID)NULL, // Create parameters
|
||
IO_FORCE_ACCESS_CHECK,
|
||
NULL
|
||
);
|
||
|
||
FREE_HEAP( fullName.Buffer );
|
||
|
||
//
|
||
// If the user didn't have this permission, update the statistics
|
||
// database.
|
||
//
|
||
|
||
if ( status == STATUS_ACCESS_DENIED ) {
|
||
SrvStatistics.AccessPermissionErrors++;
|
||
}
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
//
|
||
// The server could not open the requested name pipe,
|
||
// return the error.
|
||
//
|
||
|
||
IF_SMB_DEBUG(OPEN_CLOSE1) {
|
||
SrvPrint2( "SrvCallNamedPipe: Failed to open %ws, err=%x\n",
|
||
WorkContext->Parameters.Transaction->TransactionName.Buffer, status );
|
||
}
|
||
SrvSetSmbError (WorkContext, status);
|
||
IF_DEBUG(TRACE2) SrvPrint0( "SrvCallNamedPipe complete\n" );
|
||
return SmbTransStatusErrorWithoutData;
|
||
}
|
||
|
||
SRVDBG_CLAIM_HANDLE( fileHandle, "FIL", 15, 0 );
|
||
SrvStatistics.TotalFilesOpened++;
|
||
|
||
//
|
||
// Get a pointer to the file object, so that we can directly
|
||
// build IRPs for asynchronous operations (read and write).
|
||
// Also, get the granted access mask, so that we can prevent the
|
||
// client from doing things that it isn't allowed to do.
|
||
//
|
||
|
||
status = ObReferenceObjectByHandle(
|
||
fileHandle,
|
||
0,
|
||
NULL,
|
||
KernelMode,
|
||
(PVOID *)&fileObject,
|
||
&handleInformation
|
||
);
|
||
|
||
if ( !NT_SUCCESS(status) ) {
|
||
|
||
SrvLogServiceFailure( SRV_SVC_OB_REF_BY_HANDLE, status );
|
||
|
||
//
|
||
// This internal error bugchecks the system.
|
||
//
|
||
|
||
INTERNAL_ERROR(
|
||
ERROR_LEVEL_IMPOSSIBLE,
|
||
"SrvCallNamedPipe: unable to reference file handle 0x%lx",
|
||
fileHandle,
|
||
NULL
|
||
);
|
||
|
||
SrvSetSmbError( WorkContext, status );
|
||
IF_DEBUG(TRACE2) SrvPrint0( "SrvCallNamedPipe complete\n" );
|
||
return SmbTransStatusErrorWithoutData;
|
||
|
||
}
|
||
|
||
//
|
||
// Save file handle for the completion routine.
|
||
//
|
||
|
||
transaction = WorkContext->Parameters.Transaction;
|
||
transaction->FileHandle = fileHandle;
|
||
transaction->FileObject = fileObject;
|
||
|
||
//
|
||
// Set the pipe to message mode, so that we can preform a transceive
|
||
//
|
||
|
||
pipeInformation.CompletionMode = FILE_PIPE_QUEUE_OPERATION;
|
||
pipeInformation.ReadMode = FILE_PIPE_MESSAGE_MODE;
|
||
|
||
status = NtSetInformationFile (
|
||
fileHandle,
|
||
&ioStatusBlock,
|
||
(PVOID)&pipeInformation,
|
||
sizeof(pipeInformation),
|
||
FilePipeInformation
|
||
);
|
||
|
||
if ( !NT_SUCCESS(status) ) {
|
||
INTERNAL_ERROR(
|
||
ERROR_LEVEL_UNEXPECTED,
|
||
"SrvCallNamedPipe: NtSetInformationFile (pipe information) "
|
||
"returned %X",
|
||
status,
|
||
NULL
|
||
);
|
||
|
||
SrvLogServiceFailure( SRV_SVC_NT_SET_INFO_FILE, status );
|
||
|
||
SrvSetSmbError( WorkContext, status );
|
||
IF_DEBUG(TRACE2) SrvPrint0( "SrvCallNamedPipe complete\n" );
|
||
return SmbTransStatusErrorWithoutData;
|
||
}
|
||
|
||
//
|
||
// Set the Restart Routine addresses in the work context block.
|
||
//
|
||
|
||
WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
|
||
WorkContext->FspRestartRoutine = RestartCallNamedPipe;
|
||
|
||
transaction = WorkContext->Parameters.Transaction;
|
||
|
||
//
|
||
// Build the IRP to start a pipe transceive.
|
||
// Pass this request to NPFS.
|
||
//
|
||
|
||
//
|
||
// Inline SrvBuildIoControlRequest
|
||
//
|
||
|
||
{
|
||
|
||
//
|
||
// Get a pointer to the next stack location. This one is used to
|
||
// hold the parameters for the device I/O control request.
|
||
//
|
||
|
||
irpSp = IoGetNextIrpStackLocation( irp );
|
||
|
||
//
|
||
// Set up the completion routine.
|
||
//
|
||
|
||
IoSetCompletionRoutine(
|
||
irp,
|
||
SrvFsdIoCompletionRoutine,
|
||
(PVOID)WorkContext,
|
||
TRUE,
|
||
TRUE,
|
||
TRUE
|
||
);
|
||
|
||
irpSp->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
|
||
irpSp->MinorFunction = 0;
|
||
|
||
irpSp->DeviceObject = IoGetRelatedDeviceObject(fileObject);
|
||
irpSp->FileObject = fileObject;
|
||
|
||
irp->Tail.Overlay.OriginalFileObject = irpSp->FileObject;
|
||
irp->Tail.Overlay.Thread = WorkContext->CurrentWorkQueue->IrpThread;
|
||
DEBUG irp->RequestorMode = KernelMode;
|
||
|
||
irp->MdlAddress = NULL;
|
||
irp->AssociatedIrp.SystemBuffer = transaction->OutData;
|
||
irpSp->Parameters.DeviceIoControl.Type3InputBuffer =
|
||
transaction->InData;
|
||
|
||
//
|
||
// Copy the caller's parameters to the service-specific portion of the
|
||
// IRP for those parameters that are the same for all three methods.
|
||
//
|
||
|
||
irpSp->Parameters.FileSystemControl.OutputBufferLength =
|
||
transaction->MaxDataCount;
|
||
irpSp->Parameters.FileSystemControl.InputBufferLength =
|
||
transaction->DataCount;
|
||
irpSp->Parameters.FileSystemControl.FsControlCode =
|
||
FSCTL_PIPE_INTERNAL_TRANSCEIVE;
|
||
|
||
}
|
||
|
||
(VOID)IoCallDriver(
|
||
irpSp->DeviceObject,
|
||
irp
|
||
);
|
||
|
||
//
|
||
// The tranceive was successfully started. Return the InProgress
|
||
// status to the caller, indicating that the caller should do
|
||
// nothing further with the SMB/WorkContext at the present time.
|
||
//
|
||
|
||
IF_DEBUG(TRACE2) SrvPrint0( "SrvCallNamedPipe complete\n" );
|
||
return SmbTransStatusInProgress;
|
||
|
||
} // SrvCallNamedPipe
|
||
|
||
|
||
SMB_TRANS_STATUS
|
||
SrvWaitNamedPipe (
|
||
IN OUT PWORK_CONTEXT WorkContext
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function processes a Wait named pipe transaction SMB.
|
||
It issues an asynchronous call to NPFS. The function
|
||
completetion is handled by RestartWaitNamedPipe().
|
||
|
||
Arguments:
|
||
|
||
WorkContext - A pointer to a WORK_CONTEXT block.
|
||
|
||
Return Value:
|
||
|
||
SMB_TRANS_STATUS - Indicates whether an error occurred. See
|
||
smbtypes.h for a more complete description.
|
||
|
||
--*/
|
||
|
||
{
|
||
PFILE_PIPE_WAIT_FOR_BUFFER pipeWaitBuffer;
|
||
PREQ_TRANSACTION request;
|
||
PTRANSACTION transaction;
|
||
UNICODE_STRING pipePath;
|
||
CLONG nameLength;
|
||
|
||
PAGED_CODE( );
|
||
|
||
request = (PREQ_TRANSACTION)WorkContext->RequestParameters;
|
||
transaction = WorkContext->Parameters.Transaction;
|
||
|
||
//
|
||
// Allocate and fill in FILE_PIPE_WAIT_FOR_BUFFER structure.
|
||
//
|
||
|
||
pipePath = transaction->TransactionName;
|
||
|
||
if ( pipePath.Length <= (UNICODE_SMB_PIPE_PREFIX_LENGTH + sizeof(WCHAR)) ) {
|
||
|
||
//
|
||
// The transaction name does not include a pipe name. It's
|
||
// either \PIPE or \PIPE\, or it doesn't even have \PIPE.
|
||
//
|
||
|
||
SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
|
||
return SmbTransStatusErrorWithoutData;
|
||
|
||
}
|
||
|
||
nameLength = pipePath.Length -
|
||
(UNICODE_SMB_PIPE_PREFIX_LENGTH + sizeof(WCHAR)) +
|
||
sizeof(WCHAR);
|
||
|
||
pipeWaitBuffer = ALLOCATE_NONPAGED_POOL(
|
||
sizeof(FILE_PIPE_WAIT_FOR_BUFFER) + nameLength,
|
||
BlockTypeDataBuffer
|
||
);
|
||
|
||
if ( pipeWaitBuffer == NULL ) {
|
||
|
||
//
|
||
// We could not allocate space for the buffer to issue the
|
||
// pipe wait. Fail the request.
|
||
//
|
||
|
||
SrvSetSmbError( WorkContext, STATUS_INSUFF_SERVER_RESOURCES );
|
||
IF_DEBUG(TRACE2) SrvPrint0( "SrvWaitNamedPipe complete\n" );
|
||
return SmbTransStatusErrorWithoutData;
|
||
|
||
}
|
||
|
||
//
|
||
// Copy the pipe name not including "\PIPE\" to the pipe wait for
|
||
// buffer.
|
||
//
|
||
|
||
pipeWaitBuffer->NameLength = nameLength - sizeof(WCHAR);
|
||
|
||
RtlCopyMemory(
|
||
pipeWaitBuffer->Name,
|
||
(PUCHAR)pipePath.Buffer + UNICODE_SMB_PIPE_PREFIX_LENGTH + sizeof(WCHAR),
|
||
nameLength
|
||
);
|
||
|
||
//
|
||
// Fill in the pipe timeout value if necessary.
|
||
//
|
||
|
||
if ( SmbGetUlong( &request->Timeout ) == 0 ) {
|
||
pipeWaitBuffer->TimeoutSpecified = FALSE;
|
||
} else {
|
||
pipeWaitBuffer->TimeoutSpecified = TRUE;
|
||
|
||
//
|
||
// Convert timeout time from milliseconds to NT relative time.
|
||
//
|
||
|
||
pipeWaitBuffer->Timeout.QuadPart = -1 *
|
||
UInt32x32To64( SmbGetUlong( &request->Timeout ), 10*1000 );
|
||
}
|
||
|
||
//
|
||
// Set the Restart Routine addresses in the work context block.
|
||
//
|
||
|
||
WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
|
||
WorkContext->FspRestartRoutine = RestartWaitNamedPipe;
|
||
|
||
//
|
||
// Build a Wait named pipe IRP and pass the request to NPFS.
|
||
//
|
||
|
||
SrvBuildIoControlRequest(
|
||
WorkContext->Irp,
|
||
SrvNamedPipeFileObject,
|
||
WorkContext,
|
||
IRP_MJ_FILE_SYSTEM_CONTROL,
|
||
FSCTL_PIPE_WAIT,
|
||
pipeWaitBuffer,
|
||
sizeof(*pipeWaitBuffer) + nameLength,
|
||
NULL,
|
||
0,
|
||
NULL,
|
||
NULL
|
||
);
|
||
|
||
(VOID)IoCallDriver( SrvNamedPipeDeviceObject, WorkContext->Irp );
|
||
|
||
//
|
||
// The tranceive was successfully started. Return the InProgress
|
||
// status to the caller, indicating that the caller should do
|
||
// nothing further with the SMB/WorkContext at the present time.
|
||
//
|
||
|
||
IF_DEBUG(TRACE2) SrvPrint0( "SrvWaitNamedPipe complete\n" );
|
||
return SmbTransStatusInProgress;
|
||
|
||
} // SrvWaitNamedPipe
|
||
|
||
|
||
SMB_TRANS_STATUS
|
||
SrvQueryStateNamedPipe (
|
||
IN OUT PWORK_CONTEXT WorkContext
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function processes a Query Named pipe transaction SMB.
|
||
Since this call cannot block it is handled synchronously.
|
||
|
||
Arguments:
|
||
|
||
WorkContext - A pointer to a WORK_CONTEXT block.
|
||
|
||
Return Value:
|
||
|
||
SMB_TRANS_STATUS - Indicates whether an error occurred. See
|
||
smbtypes.h for a more complete description.
|
||
|
||
--*/
|
||
|
||
{
|
||
PREQ_TRANSACTION request;
|
||
PTRANSACTION transaction;
|
||
HANDLE pipeHandle;
|
||
IO_STATUS_BLOCK ioStatusBlock;
|
||
USHORT pipeHandleState;
|
||
FILE_PIPE_INFORMATION pipeInformation;
|
||
FILE_PIPE_LOCAL_INFORMATION pipeLocalInformation;
|
||
NTSTATUS status;
|
||
USHORT fid;
|
||
PRFCB rfcb;
|
||
|
||
PAGED_CODE( );
|
||
|
||
request = (PREQ_TRANSACTION)WorkContext->RequestParameters;
|
||
transaction = WorkContext->Parameters.Transaction;
|
||
|
||
//
|
||
// Get the FID from the second setup word and use it to generate a
|
||
// pointer to the RFCB.
|
||
//
|
||
// SrvVerifyFid will fill in WorkContext->Rfcb.
|
||
//
|
||
|
||
fid = SmbGetUshort( &transaction->InSetup[1] );
|
||
|
||
rfcb = SrvVerifyFid(
|
||
WorkContext,
|
||
fid,
|
||
FALSE,
|
||
NULL, // don't serialize with raw write
|
||
&status
|
||
);
|
||
|
||
if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
|
||
|
||
//
|
||
// Invalid file ID. Reject the request.
|
||
//
|
||
|
||
IF_DEBUG(SMB_ERRORS) {
|
||
SrvPrint1( "SrvQueryStateNamedPipe: Invalid FID: 0x%lx\n", fid );
|
||
}
|
||
|
||
SrvSetSmbError( WorkContext, STATUS_INVALID_HANDLE );
|
||
IF_DEBUG(TRACE2) SrvPrint0( "SrvQueryStateNamedPipe complete\n" );
|
||
return SmbTransStatusErrorWithoutData;
|
||
|
||
}
|
||
|
||
pipeHandle = rfcb->Lfcb->FileHandle;
|
||
|
||
status = NtQueryInformationFile (
|
||
pipeHandle,
|
||
&ioStatusBlock,
|
||
(PVOID)&pipeInformation,
|
||
sizeof(pipeInformation),
|
||
FilePipeInformation
|
||
);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
INTERNAL_ERROR(
|
||
ERROR_LEVEL_UNEXPECTED,
|
||
"SrvQueryStateNamedPipe: NtQueryInformationFile (pipe "
|
||
"information) returned %X",
|
||
status,
|
||
NULL
|
||
);
|
||
|
||
SrvLogServiceFailure( SRV_SVC_NT_QUERY_INFO_FILE, status );
|
||
|
||
SrvSetSmbError( WorkContext, status );
|
||
IF_DEBUG(TRACE2) SrvPrint0( "SrvQueryStateNamedPipe complete\n" );
|
||
return SmbTransStatusErrorWithoutData;
|
||
}
|
||
|
||
status = NtQueryInformationFile (
|
||
pipeHandle,
|
||
&ioStatusBlock,
|
||
(PVOID)&pipeLocalInformation,
|
||
sizeof(pipeLocalInformation),
|
||
FilePipeLocalInformation
|
||
);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
INTERNAL_ERROR(
|
||
ERROR_LEVEL_UNEXPECTED,
|
||
"SrvQueryStateNamedPipe: NtQueryInformationFile (pipe local "
|
||
"information) returned %X",
|
||
status,
|
||
NULL
|
||
);
|
||
|
||
SrvLogServiceFailure( SRV_SVC_NT_QUERY_INFO_FILE, status );
|
||
|
||
SrvSetSmbError( WorkContext, status );
|
||
IF_DEBUG(TRACE2) SrvPrint0( "SrvQueryStateNamedPipe complete\n" );
|
||
return SmbTransStatusErrorWithoutData;
|
||
}
|
||
|
||
//
|
||
// Query succeeded generate response
|
||
//
|
||
|
||
pipeHandleState = (USHORT)pipeInformation.CompletionMode
|
||
<< PIPE_COMPLETION_MODE_BITS;
|
||
pipeHandleState |= (USHORT)pipeLocalInformation.NamedPipeEnd
|
||
<< PIPE_PIPE_END_BITS;
|
||
pipeHandleState |= (USHORT)pipeLocalInformation.NamedPipeType
|
||
<< PIPE_PIPE_TYPE_BITS;
|
||
pipeHandleState |= (USHORT)pipeInformation.ReadMode
|
||
<< PIPE_READ_MODE_BITS;
|
||
pipeHandleState |= (USHORT)((pipeLocalInformation.MaximumInstances
|
||
<< PIPE_MAXIMUM_INSTANCES_BITS)
|
||
& SMB_PIPE_UNLIMITED_INSTANCES);
|
||
|
||
SmbPutUshort(
|
||
(PSMB_USHORT)WorkContext->Parameters.Transaction->OutParameters,
|
||
pipeHandleState
|
||
);
|
||
|
||
transaction->SetupCount = 0;
|
||
transaction->ParameterCount = sizeof(pipeHandleState);
|
||
transaction->DataCount = 0;
|
||
|
||
IF_DEBUG(TRACE2) SrvPrint0( "SrvQueryStateNamedPipe complete\n" );
|
||
return SmbTransStatusSuccess;
|
||
} // SrvQueryStateNamedPipe
|
||
|
||
|
||
SMB_TRANS_STATUS
|
||
SrvQueryInformationNamedPipe (
|
||
IN OUT PWORK_CONTEXT WorkContext
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function process a Query named pipe information transaction
|
||
SMB. This call is handled synchronously.
|
||
|
||
Arguments:
|
||
|
||
WorkContext - A pointer to a WORK_CONTEXT block.
|
||
|
||
Return Value:
|
||
|
||
SMB_TRANS_STATUS - Indicates whether an error occurred. See
|
||
smbtypes.h for a more complete description.
|
||
|
||
--*/
|
||
|
||
{
|
||
PREQ_TRANSACTION request;
|
||
PTRANSACTION transaction;
|
||
HANDLE pipeHandle;
|
||
IO_STATUS_BLOCK ioStatusBlock;
|
||
FILE_PIPE_LOCAL_INFORMATION pipeLocalInformation;
|
||
PNAMED_PIPE_INFORMATION_1 namedPipeInfo;
|
||
NTSTATUS status;
|
||
USHORT fid;
|
||
PRFCB rfcb;
|
||
PLFCB lfcb;
|
||
USHORT level;
|
||
CLONG smbPathLength;
|
||
PUNICODE_STRING pipeName;
|
||
CLONG actualDataSize;
|
||
BOOLEAN returnPipeName;
|
||
BOOLEAN isUnicode;
|
||
|
||
PAGED_CODE( );
|
||
|
||
request = (PREQ_TRANSACTION)WorkContext->RequestParameters;
|
||
transaction = WorkContext->Parameters.Transaction;
|
||
|
||
//
|
||
// Get the FID from the second setup word and use it to generate a
|
||
// pointer to the RFCB.
|
||
//
|
||
// SrvVerifyFid will fill in WorkContext->Rfcb.
|
||
//
|
||
|
||
fid = SmbGetUshort( &transaction->InSetup[1] );
|
||
rfcb = SrvVerifyFid(
|
||
WorkContext,
|
||
fid,
|
||
FALSE,
|
||
NULL, // don't serialize with raw write
|
||
&status
|
||
);
|
||
|
||
if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
|
||
|
||
//
|
||
// Invalid file ID. Reject the request.
|
||
//
|
||
|
||
IF_DEBUG(SMB_ERRORS) {
|
||
SrvPrint1( "SrvQueryStateNamedPipe: Invalid FID: 0x%lx\n", fid );
|
||
}
|
||
|
||
SrvSetSmbError( WorkContext, STATUS_INVALID_HANDLE );
|
||
IF_DEBUG(TRACE2) SrvPrint0( "SrvQueryInfoNamedPipe complete\n" );
|
||
return SmbTransStatusErrorWithoutData;
|
||
|
||
}
|
||
|
||
lfcb = rfcb->Lfcb;
|
||
pipeHandle = lfcb->FileHandle;
|
||
|
||
//
|
||
// The information level is stored in paramter byte one.
|
||
// Verify that is set correctly.
|
||
//
|
||
|
||
level = SmbGetUshort( (PSMB_USHORT)transaction->InParameters );
|
||
|
||
if ( level != 1 ) {
|
||
SrvSetSmbError( WorkContext, STATUS_INVALID_PARAMETER );
|
||
IF_DEBUG(TRACE2) SrvPrint0( "SrvQueryInfoNamedPipe complete\n" );
|
||
return SmbTransStatusErrorWithoutData;
|
||
}
|
||
|
||
//
|
||
// Now check that the response will fit. If everything expect for
|
||
// the pipe name fits, return STATUS_BUFFER_OVERFLOW with the
|
||
// fixed size portion of the data.
|
||
//
|
||
// *** Note that Unicode strings must be aligned in the SMB.
|
||
//
|
||
|
||
pipeName = &lfcb->Mfcb->FileName;
|
||
|
||
actualDataSize = sizeof(NAMED_PIPE_INFORMATION_1) - sizeof(UCHAR);
|
||
|
||
isUnicode = SMB_IS_UNICODE( WorkContext );
|
||
if ( isUnicode ) {
|
||
|
||
ASSERT( sizeof(WCHAR) == 2 );
|
||
actualDataSize = (actualDataSize + 1) & ~1; // align to SHORT
|
||
smbPathLength = (CLONG)(pipeName->Length) + sizeof(WCHAR);
|
||
|
||
} else {
|
||
|
||
smbPathLength = (CLONG)(RtlUnicodeStringToOemSize( pipeName ));
|
||
|
||
}
|
||
|
||
actualDataSize += smbPathLength;
|
||
|
||
|
||
if ( transaction->MaxDataCount <
|
||
FIELD_OFFSET(NAMED_PIPE_INFORMATION_1, PipeName ) ) {
|
||
SrvSetSmbError( WorkContext, STATUS_BUFFER_TOO_SMALL );
|
||
IF_DEBUG(TRACE2) SrvPrint0( "SrvQueryInfoNamedPipe complete\n" );
|
||
return SmbTransStatusErrorWithoutData;
|
||
}
|
||
|
||
if ( (transaction->MaxDataCount < actualDataSize) ||
|
||
(smbPathLength >= MAXIMUM_FILENAME_LENGTH) ) {
|
||
|
||
//
|
||
// Do not return the pipe name. It won't fit in the return buffer.
|
||
//
|
||
|
||
returnPipeName = FALSE;
|
||
} else {
|
||
returnPipeName = TRUE;
|
||
}
|
||
|
||
|
||
//
|
||
// Everything is correct, ask NPFS for the information.
|
||
//
|
||
|
||
status = NtQueryInformationFile (
|
||
pipeHandle,
|
||
&ioStatusBlock,
|
||
(PVOID)&pipeLocalInformation,
|
||
sizeof(pipeLocalInformation),
|
||
FilePipeLocalInformation
|
||
);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
INTERNAL_ERROR(
|
||
ERROR_LEVEL_UNEXPECTED,
|
||
"SrvQueryInformationNamedPipe: NtQueryInformationFile (pipe "
|
||
"information) returned %X",
|
||
status,
|
||
NULL
|
||
);
|
||
|
||
SrvLogServiceFailure( SRV_SVC_NT_QUERY_INFO_FILE, status );
|
||
|
||
SrvSetSmbError( WorkContext, status );
|
||
IF_DEBUG(TRACE2) SrvPrint0( "SrvQueryInfoNamedPipe complete\n" );
|
||
return SmbTransStatusErrorWithoutData;
|
||
}
|
||
|
||
//
|
||
// Query succeeded format the response data into the buffer pointed
|
||
// at by transaction->OutData
|
||
//
|
||
|
||
namedPipeInfo = (PNAMED_PIPE_INFORMATION_1)transaction->OutData;
|
||
|
||
if ((pipeLocalInformation.OutboundQuota & 0xffff0000) != 0) {
|
||
SmbPutAlignedUshort(
|
||
&namedPipeInfo->OutputBufferSize,
|
||
(USHORT)0xFFFF
|
||
);
|
||
} else {
|
||
SmbPutAlignedUshort(
|
||
&namedPipeInfo->OutputBufferSize,
|
||
(USHORT)pipeLocalInformation.OutboundQuota
|
||
);
|
||
}
|
||
|
||
if ((pipeLocalInformation.InboundQuota & 0xffff0000) != 0) {
|
||
SmbPutAlignedUshort(
|
||
&namedPipeInfo->InputBufferSize,
|
||
(USHORT)0xFFFF
|
||
);
|
||
} else {
|
||
SmbPutAlignedUshort(
|
||
&namedPipeInfo->InputBufferSize,
|
||
(USHORT)pipeLocalInformation.InboundQuota
|
||
);
|
||
}
|
||
|
||
if ((pipeLocalInformation.MaximumInstances & 0xffffff00) != 0) {
|
||
namedPipeInfo->MaximumInstances = (UCHAR)0xFF;
|
||
} else {
|
||
namedPipeInfo->MaximumInstances =
|
||
(UCHAR)pipeLocalInformation.MaximumInstances;
|
||
}
|
||
|
||
if ((pipeLocalInformation.CurrentInstances & 0xffffff00) != 0) {
|
||
namedPipeInfo->CurrentInstances = (UCHAR)0xFF;
|
||
} else {
|
||
namedPipeInfo->CurrentInstances =
|
||
(UCHAR)pipeLocalInformation.CurrentInstances;
|
||
}
|
||
|
||
if ( returnPipeName ) {
|
||
|
||
//
|
||
// Copy full pipe path name to the output buffer, appending a NUL.
|
||
//
|
||
// *** Note that Unicode pipe names must be aligned in the SMB.
|
||
//
|
||
|
||
namedPipeInfo->PipeNameLength = (UCHAR)smbPathLength;
|
||
|
||
if ( isUnicode ) {
|
||
|
||
PVOID buffer = ALIGN_SMB_WSTR( namedPipeInfo->PipeName );
|
||
|
||
RtlCopyMemory( buffer, pipeName->Buffer, smbPathLength );
|
||
|
||
} else {
|
||
|
||
UNICODE_STRING source;
|
||
OEM_STRING destination;
|
||
|
||
source.Buffer = pipeName->Buffer;
|
||
source.Length = pipeName->Length;
|
||
source.MaximumLength = source.Length;
|
||
|
||
destination.Buffer = (PCHAR) namedPipeInfo->PipeName;
|
||
destination.MaximumLength = (USHORT)smbPathLength;
|
||
|
||
RtlUnicodeStringToOemString(
|
||
&destination,
|
||
&source,
|
||
FALSE
|
||
);
|
||
|
||
}
|
||
|
||
transaction->DataCount = actualDataSize;
|
||
|
||
} else {
|
||
|
||
SrvSetSmbError2( WorkContext, STATUS_BUFFER_OVERFLOW, TRUE );
|
||
transaction->DataCount =
|
||
FIELD_OFFSET( NAMED_PIPE_INFORMATION_1, PipeName );
|
||
|
||
}
|
||
|
||
//
|
||
// Set up to send success response
|
||
//
|
||
|
||
transaction->SetupCount = 0;
|
||
transaction->ParameterCount = 0;
|
||
|
||
IF_DEBUG(TRACE2) SrvPrint0( "SrvQueryInfoNamedPipe complete\n" );
|
||
|
||
if ( returnPipeName) {
|
||
return SmbTransStatusSuccess;
|
||
} else {
|
||
return SmbTransStatusErrorWithData;
|
||
}
|
||
|
||
} // SrvQueryInformationNamedPipe
|
||
|
||
|
||
SMB_TRANS_STATUS
|
||
SrvSetStateNamedPipe (
|
||
IN OUT PWORK_CONTEXT WorkContext
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function processes a set named pipe handle state transaction
|
||
SMB. The call is issued synchronously.
|
||
|
||
Arguments:
|
||
|
||
WorkContext - A pointer to a WORK_CONTEXT block.
|
||
|
||
Return Value:
|
||
|
||
SMB_TRANS_STATUS - Indicates whether an error occurred. See
|
||
smbtypes.h for a more complete description.
|
||
|
||
--*/
|
||
|
||
{
|
||
PREQ_TRANSACTION request;
|
||
PTRANSACTION transaction;
|
||
HANDLE pipeHandle;
|
||
IO_STATUS_BLOCK ioStatusBlock;
|
||
USHORT pipeHandleState;
|
||
FILE_PIPE_INFORMATION pipeInformation;
|
||
NTSTATUS status;
|
||
USHORT fid;
|
||
PRFCB rfcb;
|
||
|
||
PAGED_CODE( );
|
||
|
||
request = (PREQ_TRANSACTION)WorkContext->RequestParameters;
|
||
transaction = WorkContext->Parameters.Transaction;
|
||
|
||
//
|
||
// Get the FID from the second setup word and use it to generate a
|
||
// pointer to the RFCB.
|
||
//
|
||
// SrvVerifyFid will fill in WorkContext->Rfcb.
|
||
//
|
||
|
||
fid = SmbGetUshort( &transaction->InSetup[1] );
|
||
rfcb = SrvVerifyFid(
|
||
WorkContext,
|
||
fid,
|
||
FALSE,
|
||
NULL, // don't serialize with raw write
|
||
&status
|
||
);
|
||
|
||
if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
|
||
|
||
//
|
||
// Invalid file ID. Reject the request.
|
||
//
|
||
|
||
IF_DEBUG(SMB_ERRORS) {
|
||
SrvPrint1( "SrvSetStateNamedPipe: Invalid FID: 0x%lx\n", fid );
|
||
}
|
||
|
||
SrvSetSmbError( WorkContext, STATUS_INVALID_HANDLE );
|
||
IF_DEBUG(TRACE2) SrvPrint0( "SrvSetStateNamedPipe complete\n" );
|
||
return SmbTransStatusErrorWithoutData;
|
||
|
||
}
|
||
|
||
pipeHandle = rfcb->Lfcb->FileHandle;
|
||
|
||
//
|
||
// The SMB contains 2 parameter bytes. Translate these to
|
||
// NT format, then attempt to set the named pipe handle state.
|
||
//
|
||
|
||
pipeHandleState = SmbGetUshort(
|
||
(PSMB_USHORT)
|
||
WorkContext->Parameters.Transaction->InParameters
|
||
);
|
||
|
||
pipeInformation.CompletionMode =
|
||
((ULONG)pipeHandleState >> PIPE_COMPLETION_MODE_BITS) & 1;
|
||
pipeInformation.ReadMode =
|
||
((ULONG)pipeHandleState >> PIPE_READ_MODE_BITS) & 1;
|
||
|
||
|
||
status = NtSetInformationFile (
|
||
pipeHandle,
|
||
&ioStatusBlock,
|
||
(PVOID)&pipeInformation,
|
||
sizeof(pipeInformation),
|
||
FilePipeInformation
|
||
);
|
||
|
||
if (NT_SUCCESS(status) ) {
|
||
status = ioStatusBlock.Status;
|
||
}
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
INTERNAL_ERROR(
|
||
ERROR_LEVEL_UNEXPECTED,
|
||
"SrvSetStateNamedPipe: NetSetInformationFile (pipe information) "
|
||
"returned %X",
|
||
status,
|
||
NULL
|
||
);
|
||
|
||
SrvLogServiceFailure( SRV_SVC_NT_SET_INFO_FILE, status );
|
||
|
||
SrvSetSmbError( WorkContext, status );
|
||
IF_DEBUG(TRACE2) SrvPrint0( "SrvSetStateNamedPipe complete\n" );
|
||
return SmbTransStatusErrorWithoutData;
|
||
}
|
||
|
||
//
|
||
// Success. Update our internal pipe handle state.
|
||
//
|
||
|
||
rfcb->BlockingModePipe =
|
||
(BOOLEAN)(pipeInformation.CompletionMode ==
|
||
FILE_PIPE_QUEUE_OPERATION);
|
||
rfcb->ByteModePipe =
|
||
(BOOLEAN)(pipeInformation.ReadMode == FILE_PIPE_BYTE_STREAM_MODE);
|
||
|
||
//
|
||
// Now set up for the success response.
|
||
//
|
||
|
||
transaction->SetupCount = 0;
|
||
transaction->ParameterCount = 0;
|
||
transaction->DataCount = 0;
|
||
|
||
IF_DEBUG(TRACE2) SrvPrint0( "SrvSetStateNamedPipe complete\n" );
|
||
return SmbTransStatusSuccess;
|
||
|
||
} // SrvSetStateNamedPipe
|
||
|
||
|
||
SMB_TRANS_STATUS
|
||
SrvPeekNamedPipe (
|
||
IN OUT PWORK_CONTEXT WorkContext
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function handles a peek named pipe transaction SMB. The
|
||
call is issued asynchrously and is completed by RestartPeekNamedPipe().
|
||
|
||
Arguments:
|
||
|
||
WorkContext - A pointer to a WORK_CONTEXT block.
|
||
|
||
Return Value:
|
||
|
||
status - The result of the operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
PTRANSACTION transaction;
|
||
USHORT fid;
|
||
PRFCB rfcb;
|
||
PLFCB lfcb;
|
||
NTSTATUS status;
|
||
|
||
PAGED_CODE( );
|
||
|
||
transaction = WorkContext->Parameters.Transaction;
|
||
|
||
//
|
||
// Get the FID from the second setup word and use it to generate a
|
||
// pointer to the RFCB.
|
||
//
|
||
// SrvVerifyFid will fill in WorkContext->Rfcb.
|
||
//
|
||
|
||
fid = SmbGetUshort( &transaction->InSetup[1] );
|
||
rfcb = SrvVerifyFid(
|
||
WorkContext,
|
||
fid,
|
||
FALSE,
|
||
SrvRestartExecuteTransaction, // serialize with raw write
|
||
&status
|
||
);
|
||
|
||
if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
|
||
|
||
if ( !NT_SUCCESS( status ) ) {
|
||
|
||
//
|
||
// Invalid file ID. Reject the request.
|
||
//
|
||
|
||
IF_DEBUG(SMB_ERRORS) {
|
||
SrvPrint1( "SrvPeekNamedPipe: Invalid FID: 0x%lx\n", fid );
|
||
}
|
||
|
||
SrvSetSmbError( WorkContext, STATUS_INVALID_HANDLE );
|
||
IF_DEBUG(TRACE2) SrvPrint0( "SrvPeekNamedPipe complete\n" );
|
||
return SmbTransStatusErrorWithoutData;
|
||
|
||
}
|
||
|
||
|
||
//
|
||
// The work item has been queued because a raw write is in
|
||
// progress.
|
||
//
|
||
|
||
return SmbTransStatusInProgress;
|
||
|
||
}
|
||
|
||
//
|
||
// Set the Restart Routine addresses in the work context block.
|
||
//
|
||
|
||
WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
|
||
WorkContext->FspRestartRoutine = RestartPeekNamedPipe;
|
||
|
||
//
|
||
// Issue the request to NPFS. We expect both parameters and
|
||
// data to be returned. The buffer which we offer is contiguous
|
||
// and large enough to contain both.
|
||
//
|
||
|
||
transaction = WorkContext->Parameters.Transaction;
|
||
lfcb = rfcb->Lfcb;
|
||
|
||
SrvBuildIoControlRequest(
|
||
WorkContext->Irp,
|
||
lfcb->FileObject,
|
||
WorkContext,
|
||
IRP_MJ_FILE_SYSTEM_CONTROL,
|
||
FSCTL_PIPE_PEEK,
|
||
transaction->OutParameters,
|
||
0,
|
||
NULL,
|
||
transaction->MaxParameterCount + transaction->MaxDataCount,
|
||
NULL,
|
||
NULL
|
||
);
|
||
|
||
//
|
||
// Pass the request to NPFS.
|
||
//
|
||
|
||
(VOID)IoCallDriver( lfcb->DeviceObject, WorkContext->Irp );
|
||
|
||
//
|
||
// The peek was successfully started. Return the InProgress
|
||
// status to the caller, indicating that the caller should do
|
||
// nothing further with the SMB/WorkContext at the present time.
|
||
//
|
||
|
||
IF_DEBUG(TRACE2) SrvPrint0( "SrvPeekNamedPipe complete\n" );
|
||
return SmbTransStatusInProgress;
|
||
|
||
} // SrvPeekNamedPipe
|
||
|
||
|
||
SMB_TRANS_STATUS
|
||
SrvTransactNamedPipe (
|
||
IN OUT PWORK_CONTEXT WorkContext
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function handles the transact named pipe transaction SMB.
|
||
The call to NPFS is issued asynchronously and is completed by
|
||
RestartTransactNamedPipe()
|
||
|
||
Arguments:
|
||
|
||
WorkContext - A pointer to a WORK_CONTEXT block.
|
||
|
||
Return Value:
|
||
|
||
SMB_TRANS_STATUS - Indicates whether an error occurred. See
|
||
smbtypes.h for a more complete description.
|
||
|
||
--*/
|
||
|
||
{
|
||
PTRANSACTION transaction;
|
||
USHORT fid;
|
||
PRFCB rfcb;
|
||
NTSTATUS status;
|
||
PIO_STACK_LOCATION irpSp;
|
||
PIRP irp = WorkContext->Irp;
|
||
|
||
PAGED_CODE( );
|
||
|
||
transaction = WorkContext->Parameters.Transaction;
|
||
|
||
//
|
||
// Get the FID from the second setup word and use it to generate a
|
||
// pointer to the RFCB.
|
||
//
|
||
// SrvVerifyFid will fill in WorkContext->Rfcb.
|
||
//
|
||
|
||
fid = SmbGetUshort( &transaction->InSetup[1] );
|
||
|
||
rfcb = SrvVerifyFid(
|
||
WorkContext,
|
||
fid,
|
||
FALSE,
|
||
SrvRestartExecuteTransaction, // serialize with raw write
|
||
&status
|
||
);
|
||
|
||
if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
|
||
|
||
if ( !NT_SUCCESS( status ) ) {
|
||
|
||
//
|
||
// Invalid file ID. Reject the request.
|
||
//
|
||
|
||
IF_DEBUG(SMB_ERRORS) {
|
||
SrvPrint1( "SrvTransactStateNamedPipe: Invalid FID: 0x%lx\n",
|
||
fid );
|
||
}
|
||
|
||
SrvSetSmbError( WorkContext, STATUS_INVALID_HANDLE );
|
||
IF_DEBUG(TRACE2) SrvPrint0( "SrvTransactNamedPipe complete\n" );
|
||
return SmbTransStatusErrorWithoutData;
|
||
|
||
}
|
||
|
||
//
|
||
// The work item has been queued because a raw write is in
|
||
// progress.
|
||
//
|
||
|
||
return SmbTransStatusInProgress;
|
||
|
||
}
|
||
|
||
//
|
||
// Set the Restart Routine addresses in the work context block.
|
||
//
|
||
|
||
WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
|
||
WorkContext->FspRestartRoutine = RestartTransactNamedPipe;
|
||
|
||
transaction = WorkContext->Parameters.Transaction;
|
||
|
||
//
|
||
// Inline SrvBuildIoControlRequest
|
||
//
|
||
|
||
{
|
||
|
||
//
|
||
// Get a pointer to the next stack location. This one is used to
|
||
// hold the parameters for the device I/O control request.
|
||
//
|
||
|
||
irpSp = IoGetNextIrpStackLocation( irp );
|
||
|
||
//
|
||
// Set up the completion routine.
|
||
//
|
||
|
||
IoSetCompletionRoutine(
|
||
irp,
|
||
SrvFsdIoCompletionRoutine,
|
||
(PVOID)WorkContext,
|
||
TRUE,
|
||
TRUE,
|
||
TRUE
|
||
);
|
||
|
||
irpSp->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
|
||
irpSp->MinorFunction = 0;
|
||
|
||
irpSp->DeviceObject = rfcb->Lfcb->DeviceObject;
|
||
irpSp->FileObject = rfcb->Lfcb->FileObject;
|
||
|
||
irp->Tail.Overlay.OriginalFileObject = irpSp->FileObject;
|
||
irp->Tail.Overlay.Thread = WorkContext->CurrentWorkQueue->IrpThread;
|
||
DEBUG irp->RequestorMode = KernelMode;
|
||
|
||
irp->MdlAddress = NULL;
|
||
irp->AssociatedIrp.SystemBuffer = transaction->OutData;
|
||
irpSp->Parameters.DeviceIoControl.Type3InputBuffer =
|
||
transaction->InData;
|
||
|
||
//
|
||
// Copy the caller's parameters to the service-specific portion of the
|
||
// IRP for those parameters that are the same for all three methods.
|
||
//
|
||
|
||
irpSp->Parameters.FileSystemControl.OutputBufferLength =
|
||
transaction->MaxDataCount;
|
||
irpSp->Parameters.FileSystemControl.InputBufferLength =
|
||
transaction->DataCount;
|
||
irpSp->Parameters.FileSystemControl.FsControlCode =
|
||
FSCTL_PIPE_INTERNAL_TRANSCEIVE;
|
||
|
||
}
|
||
|
||
//
|
||
// Pass the request to NPFS.
|
||
//
|
||
|
||
(VOID)IoCallDriver( irpSp->DeviceObject, irp );
|
||
|
||
//
|
||
// The tranceive was successfully started. Return the InProgress
|
||
// status to the caller, indicating that the caller should do
|
||
// nothing further with the SMB/WorkContext at the present time.
|
||
//
|
||
|
||
IF_DEBUG(TRACE2) SrvPrint0( "SrvTransactNamedPipe complete\n" );
|
||
return SmbTransStatusInProgress;
|
||
|
||
} // SrvTransactNamedPipe
|
||
|
||
BOOLEAN
|
||
SrvFastTransactNamedPipe (
|
||
IN OUT PWORK_CONTEXT WorkContext,
|
||
OUT SMB_STATUS * SmbStatus
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function handles the special case of a single buffer transact
|
||
named pipe transaction SMB. The call to NPFS is issued asynchronously
|
||
and is completed by RestartFastTransactNamedPipe()
|
||
|
||
Arguments:
|
||
|
||
WorkContext - A pointer to a WORK_CONTEXT block.
|
||
SmbStatus - Status of the transaction.
|
||
|
||
Return Value:
|
||
|
||
TRUE, if fastpath succeeded,
|
||
FALSE, otherwise. Server must take long path.
|
||
|
||
--*/
|
||
|
||
{
|
||
USHORT fid;
|
||
PRFCB rfcb;
|
||
PSESSION session;
|
||
NTSTATUS status;
|
||
PIO_STACK_LOCATION irpSp;
|
||
PIRP irp = WorkContext->Irp;
|
||
CLONG outputBufferSize;
|
||
CLONG maxParameterCount;
|
||
CLONG maxDataCount;
|
||
|
||
PSMB_USHORT inSetup;
|
||
PSMB_USHORT outSetup;
|
||
PCHAR outParam;
|
||
PCHAR outData;
|
||
CLONG offset;
|
||
CLONG setupOffset;
|
||
|
||
PREQ_TRANSACTION request;
|
||
PRESP_TRANSACTION response;
|
||
PSMB_HEADER header;
|
||
|
||
PAGED_CODE( );
|
||
|
||
header = WorkContext->ResponseHeader;
|
||
request = (PREQ_TRANSACTION)WorkContext->RequestParameters;
|
||
response = (PRESP_TRANSACTION)WorkContext->ResponseParameters;
|
||
|
||
//
|
||
// Get the FID from the second setup word and use it to generate a
|
||
// pointer to the RFCB.
|
||
//
|
||
// SrvVerifyFid will fill in WorkContext->Rfcb.
|
||
//
|
||
|
||
setupOffset = (CLONG)((CLONG_PTR)(request->Buffer) - (CLONG_PTR)header);
|
||
inSetup = (PSMB_USHORT)( (PCHAR)header + setupOffset );
|
||
|
||
fid = SmbGetUshort( &inSetup[1] );
|
||
rfcb = SrvVerifyFid(
|
||
WorkContext,
|
||
fid,
|
||
FALSE,
|
||
SrvRestartSmbReceived, // serialize with raw write
|
||
&status
|
||
);
|
||
|
||
if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
|
||
|
||
if ( !NT_SUCCESS( status ) ) {
|
||
|
||
//
|
||
// Invalid file ID. Reject the request.
|
||
//
|
||
|
||
IF_DEBUG(SMB_ERRORS) {
|
||
SrvPrint1( "SrvTransactStateNamedPipe: Invalid FID: 0x%lx\n",
|
||
fid );
|
||
}
|
||
|
||
SrvSetSmbError( WorkContext, STATUS_INVALID_HANDLE );
|
||
IF_DEBUG(TRACE2) SrvPrint0( "SrvTransactNamedPipe complete\n" );
|
||
*SmbStatus = SmbStatusSendResponse;
|
||
return TRUE;
|
||
|
||
}
|
||
|
||
//
|
||
// The work item has been queued because a raw write is in
|
||
// progress.
|
||
//
|
||
|
||
*SmbStatus = SmbStatusInProgress;
|
||
return TRUE;
|
||
|
||
}
|
||
|
||
//
|
||
// See and see if all the data will fit into the response buffer.
|
||
// Reject the long path if not the case.
|
||
// The "+1" on the MaxSetupCount calculation below accounts for the
|
||
// USHORT byte count in the buffer.
|
||
//
|
||
|
||
maxParameterCount = SmbGetUshort( &request->MaxParameterCount );
|
||
maxDataCount = SmbGetUshort( &request->MaxDataCount );
|
||
session = rfcb->Lfcb->Session;
|
||
outputBufferSize = ((maxParameterCount * sizeof(CHAR) + 3) & ~3) +
|
||
((maxDataCount * sizeof(CHAR) + 3) & ~3) +
|
||
(((request->MaxSetupCount + 1) * sizeof(USHORT) + 3) & ~3);
|
||
|
||
if ( sizeof(SMB_HEADER) +
|
||
sizeof (RESP_TRANSACTION) +
|
||
outputBufferSize
|
||
> (ULONG)session->MaxBufferSize) {
|
||
|
||
//
|
||
// This won't fit. Use the long path.
|
||
//
|
||
|
||
return(FALSE);
|
||
}
|
||
|
||
//
|
||
// If this operation may block, and we are running short of
|
||
// free work items, fail this SMB with an out of resources error.
|
||
//
|
||
|
||
if ( SrvReceiveBufferShortage( ) ) {
|
||
|
||
SrvStatistics.BlockingSmbsRejected++;
|
||
|
||
SrvSetSmbError(
|
||
WorkContext,
|
||
STATUS_INSUFF_SERVER_RESOURCES
|
||
);
|
||
|
||
*SmbStatus = SmbStatusSendResponse;
|
||
return TRUE;
|
||
|
||
} else {
|
||
|
||
//
|
||
// SrvBlockingOpsInProgress has already been incremented.
|
||
// Flag this work item as a blocking operation.
|
||
//
|
||
|
||
WorkContext->BlockingOperation = TRUE;
|
||
|
||
}
|
||
|
||
//
|
||
// Set the Restart Routine addresses in the work context block.
|
||
//
|
||
|
||
DEBUG WorkContext->FsdRestartRoutine = NULL;
|
||
|
||
//
|
||
// Setup pointers and locals.
|
||
//
|
||
|
||
outSetup = (PSMB_USHORT)response->Buffer;
|
||
|
||
//
|
||
// The "+1" on the end of the following calculation is to account
|
||
// for the USHORT byte count, which could overwrite data in certain
|
||
// cases should the MaxSetupCount be 0.
|
||
//
|
||
|
||
outParam = (PCHAR)(outSetup + (request->MaxSetupCount + 1));
|
||
offset = (CLONG)((outParam - (PCHAR)header + 3) & ~3);
|
||
outParam = (PCHAR)header + offset;
|
||
|
||
outData = outParam + maxParameterCount;
|
||
offset = (CLONG)((outData - (PCHAR)header + 3) & ~3);
|
||
outData = (PCHAR)header + offset;
|
||
|
||
//
|
||
// Fill in the work context parameters.
|
||
//
|
||
|
||
WorkContext->Parameters.FastTransactNamedPipe.OutSetup = outSetup;
|
||
WorkContext->Parameters.FastTransactNamedPipe.OutParam = outParam;
|
||
WorkContext->Parameters.FastTransactNamedPipe.OutData = outData;
|
||
|
||
//
|
||
// Inline SrvBuildIoControlRequest
|
||
//
|
||
|
||
{
|
||
//
|
||
// Get a pointer to the next stack location. This one is used to
|
||
// hold the parameters for the device I/O control request.
|
||
//
|
||
|
||
irpSp = IoGetNextIrpStackLocation( irp );
|
||
|
||
//
|
||
// Set up the completion routine.
|
||
//
|
||
|
||
IoSetCompletionRoutine(
|
||
irp,
|
||
RestartFastTransactNamedPipe,
|
||
(PVOID)WorkContext,
|
||
TRUE,
|
||
TRUE,
|
||
TRUE
|
||
);
|
||
|
||
irpSp->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
|
||
irpSp->MinorFunction = 0;
|
||
|
||
irpSp->DeviceObject = rfcb->Lfcb->DeviceObject;
|
||
irpSp->FileObject = rfcb->Lfcb->FileObject;
|
||
|
||
irp->Tail.Overlay.OriginalFileObject = irpSp->FileObject;
|
||
irp->Tail.Overlay.Thread = WorkContext->CurrentWorkQueue->IrpThread;
|
||
DEBUG irp->RequestorMode = KernelMode;
|
||
|
||
irp->MdlAddress = NULL;
|
||
irp->AssociatedIrp.SystemBuffer = outData;
|
||
irpSp->Parameters.DeviceIoControl.Type3InputBuffer =
|
||
(PCHAR)header + SmbGetUshort( &request->DataOffset );
|
||
|
||
//
|
||
// Copy the caller's parameters to the service-specific portion of the
|
||
// IRP for those parameters that are the same for all three methods.
|
||
//
|
||
|
||
irpSp->Parameters.FileSystemControl.OutputBufferLength = maxDataCount;
|
||
irpSp->Parameters.FileSystemControl.InputBufferLength =
|
||
SmbGetUshort( &request->DataCount );
|
||
irpSp->Parameters.FileSystemControl.FsControlCode =
|
||
FSCTL_PIPE_INTERNAL_TRANSCEIVE;
|
||
|
||
}
|
||
|
||
//
|
||
// Pass the request to NPFS.
|
||
//
|
||
|
||
(VOID)IoCallDriver( irpSp->DeviceObject, irp );
|
||
|
||
//
|
||
// The tranceive was successfully started. Return the InProgress
|
||
// status to the caller, indicating that the caller should do
|
||
// nothing further with the SMB/WorkContext at the present time.
|
||
//
|
||
|
||
IF_DEBUG(TRACE2) SrvPrint0( "SrvTransactNamedPipe complete\n" );
|
||
*SmbStatus = SmbStatusInProgress;
|
||
return TRUE;
|
||
|
||
} // SrvFastTransactNamedPipe
|
||
|
||
|
||
SMB_TRANS_STATUS
|
||
SrvRawWriteNamedPipe (
|
||
IN OUT PWORK_CONTEXT WorkContext
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function handles the raw write named pipe transaction SMB.
|
||
The call to NPFS is issued asynchronously and is completed by
|
||
RestartRawWriteNamedPipe().
|
||
|
||
Arguments:
|
||
|
||
WorkContext - A pointer to a WORK_CONTEXT block.
|
||
|
||
Return Value:
|
||
|
||
SMB_TRANS_STATUS - Indicates whether an error occurred. See
|
||
smbtypes.h for a more complete description.
|
||
|
||
--*/
|
||
|
||
{
|
||
PTRANSACTION transaction;
|
||
USHORT fid;
|
||
PRFCB rfcb;
|
||
NTSTATUS status;
|
||
|
||
PAGED_CODE( );
|
||
|
||
transaction = WorkContext->Parameters.Transaction;
|
||
|
||
//
|
||
// Get the FID from the second setup word and use it to generate a
|
||
// pointer to the RFCB.
|
||
//
|
||
// SrvVerifyFid will fill in WorkContext->Rfcb.
|
||
//
|
||
|
||
fid = SmbGetUshort( &transaction->InSetup[1] );
|
||
|
||
rfcb = SrvVerifyFid(
|
||
WorkContext,
|
||
fid,
|
||
FALSE,
|
||
SrvRestartExecuteTransaction, // serialize with raw write
|
||
&status
|
||
);
|
||
|
||
if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
|
||
|
||
if ( !NT_SUCCESS( status ) ) {
|
||
|
||
//
|
||
// Invalid file ID. Reject the request.
|
||
//
|
||
|
||
IF_DEBUG(SMB_ERRORS) {
|
||
SrvPrint1( "SrvRawWriteStateNamedPipe: Invalid FID: 0x%lx\n",
|
||
fid );
|
||
}
|
||
|
||
SrvSetSmbError( WorkContext, STATUS_INVALID_HANDLE );
|
||
IF_DEBUG(TRACE2) SrvPrint0( "SrvRawWriteNamedPipe complete\n" );
|
||
return SmbTransStatusErrorWithoutData;
|
||
|
||
}
|
||
|
||
//
|
||
// The work item has been queued because a raw write is in
|
||
// progress.
|
||
//
|
||
|
||
return SmbTransStatusInProgress;
|
||
|
||
}
|
||
|
||
//
|
||
// We only allow the special 0 bytes message mode write. Otherwise
|
||
// reject the request.
|
||
//
|
||
|
||
if ( transaction->DataCount != 2 ||
|
||
transaction->InData[0] != 0 ||
|
||
transaction->InData[1] != 0 ||
|
||
rfcb->ByteModePipe ) {
|
||
|
||
SrvSetSmbError( WorkContext, STATUS_INVALID_PARAMETER );
|
||
return SmbTransStatusErrorWithoutData;
|
||
|
||
}
|
||
|
||
//
|
||
// Set the Restart Routine addresses in the work context block.
|
||
//
|
||
|
||
WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
|
||
WorkContext->FspRestartRoutine = RestartRawWriteNamedPipe;
|
||
|
||
SrvBuildIoControlRequest(
|
||
WorkContext->Irp,
|
||
rfcb->Lfcb->FileObject,
|
||
WorkContext,
|
||
IRP_MJ_FILE_SYSTEM_CONTROL,
|
||
FSCTL_PIPE_INTERNAL_WRITE,
|
||
transaction->InData,
|
||
0,
|
||
NULL,
|
||
0,
|
||
NULL,
|
||
NULL
|
||
);
|
||
|
||
//
|
||
// Pass the request to NPFS.
|
||
//
|
||
|
||
IoCallDriver( rfcb->Lfcb->DeviceObject, WorkContext->Irp );
|
||
|
||
//
|
||
// The write was successfully started. Return the InProgress
|
||
// status to the caller, indicating that the caller should do
|
||
// nothing further with the SMB/WorkContext at the present time.
|
||
//
|
||
|
||
IF_DEBUG(TRACE2) SrvPrint0( "SrvRawWriteNamedPipe complete\n" );
|
||
return SmbTransStatusInProgress;
|
||
|
||
} // SrvRawWriteNamedPipe
|
||
|
||
|
||
VOID SRVFASTCALL
|
||
RestartCallNamedPipe (
|
||
IN OUT PWORK_CONTEXT WorkContext
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the completion routine for SrvCallNamedPipe
|
||
|
||
Arguments:
|
||
|
||
WorkContext - A pointer to a WORK_CONTEXT block.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS status;
|
||
PTRANSACTION transaction;
|
||
|
||
PAGED_CODE( );
|
||
|
||
//
|
||
// If the transceive request failed, set an error status in the response
|
||
// header.
|
||
//
|
||
|
||
status = WorkContext->Irp->IoStatus.Status;
|
||
transaction = WorkContext->Parameters.Transaction;
|
||
|
||
if ( status == STATUS_BUFFER_OVERFLOW ) {
|
||
|
||
//
|
||
// Down level clients, expect us to return STATUS_SUCCESS.
|
||
//
|
||
|
||
if ( !IS_NT_DIALECT( WorkContext->Connection->SmbDialect ) ) {
|
||
status = STATUS_SUCCESS;
|
||
|
||
} else {
|
||
|
||
//
|
||
// The buffer we supplied is not big enough. Set the
|
||
// error fields in the SMB, but continue so that we send
|
||
// all the information.
|
||
//
|
||
|
||
SrvSetSmbError2( WorkContext, STATUS_BUFFER_OVERFLOW, TRUE );
|
||
|
||
}
|
||
|
||
} else if ( !NT_SUCCESS(status) ) {
|
||
|
||
IF_DEBUG(ERRORS) {
|
||
SrvPrint1( "RestartCallNamedPipe: Pipe transceive failed: %X\n",
|
||
status );
|
||
}
|
||
SrvSetSmbError( WorkContext, status );
|
||
|
||
} else {
|
||
|
||
//
|
||
// Success. Prepare to generate and send the response.
|
||
//
|
||
|
||
transaction->SetupCount = 0;
|
||
transaction->ParameterCount = 0;
|
||
transaction->DataCount = (ULONG)WorkContext->Irp->IoStatus.Information;
|
||
|
||
}
|
||
|
||
//
|
||
// Close the open pipe handle.
|
||
//
|
||
|
||
SRVDBG_RELEASE_HANDLE( transaction->FileHandle, "FIL", 19, transaction );
|
||
SrvNtClose( transaction->FileHandle, TRUE );
|
||
ObDereferenceObject( transaction->FileObject );
|
||
|
||
//
|
||
// Respond to the client
|
||
//
|
||
|
||
if ( NT_SUCCESS(status) ) {
|
||
SrvCompleteExecuteTransaction(WorkContext, SmbTransStatusSuccess);
|
||
} else if ( status == STATUS_BUFFER_OVERFLOW ) {
|
||
SrvCompleteExecuteTransaction(WorkContext, SmbTransStatusErrorWithData);
|
||
} else {
|
||
IF_DEBUG(ERRORS) SrvPrint1( "Pipe call failed: %X\n", status );
|
||
SrvSetSmbError( WorkContext, status );
|
||
SrvCompleteExecuteTransaction(
|
||
WorkContext,
|
||
SmbTransStatusErrorWithoutData
|
||
);
|
||
}
|
||
|
||
IF_DEBUG(TRACE2) SrvPrint0( "RestartCallNamedPipe complete\n" );
|
||
return;
|
||
|
||
} // RestartCallNamedPipe
|
||
|
||
|
||
VOID SRVFASTCALL
|
||
RestartWaitNamedPipe (
|
||
IN OUT PWORK_CONTEXT WorkContext
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the completion routine for SrvWaitNamedPipe
|
||
|
||
Arguments:
|
||
|
||
WorkContext - A pointer to a WORK_CONTEXT block.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PTRANSACTION transaction;
|
||
NTSTATUS status;
|
||
|
||
PAGED_CODE( );
|
||
|
||
//
|
||
// Deallocate the wait buffer.
|
||
//
|
||
|
||
DEALLOCATE_NONPAGED_POOL( WorkContext->Irp->AssociatedIrp.SystemBuffer );
|
||
|
||
//
|
||
// If the wait request failed, set an error status in the response
|
||
// header.
|
||
//
|
||
|
||
status = WorkContext->Irp->IoStatus.Status;
|
||
|
||
if ( !NT_SUCCESS(status) ) {
|
||
IF_DEBUG(ERRORS) SrvPrint1( "Pipe wait failed: %X\n", status );
|
||
SrvSetSmbError( WorkContext, status );
|
||
SrvCompleteExecuteTransaction(
|
||
WorkContext,
|
||
SmbTransStatusErrorWithoutData
|
||
);
|
||
IF_DEBUG(TRACE2) SrvPrint0( "RestartWaitNamedPipe complete\n" );
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Success. Prepare to generate and send the response.
|
||
//
|
||
|
||
transaction = WorkContext->Parameters.Transaction;
|
||
|
||
transaction->SetupCount = 0;
|
||
transaction->ParameterCount = 0;
|
||
transaction->DataCount = 0;
|
||
|
||
//
|
||
// Generate and send the response.
|
||
//
|
||
|
||
SrvCompleteExecuteTransaction(WorkContext, SmbTransStatusSuccess);
|
||
IF_DEBUG(TRACE2) SrvPrint0( "RestartWaitNamedPipe complete\n" );
|
||
return;
|
||
|
||
} // RestartWaitNamedPipe
|
||
|
||
|
||
VOID SRVFASTCALL
|
||
RestartPeekNamedPipe (
|
||
IN OUT PWORK_CONTEXT WorkContext
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the completion routine for PeekNamedPipe
|
||
|
||
Arguments:
|
||
|
||
WorkContext - A pointer to a WORK_CONTEXT block.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS status;
|
||
PFILE_PIPE_PEEK_BUFFER pipePeekBuffer;
|
||
PRESP_PEEK_NMPIPE respPeekNmPipe;
|
||
USHORT readDataAvailable, messageLength, namedPipeState;
|
||
PTRANSACTION transaction;
|
||
|
||
PAGED_CODE( );
|
||
|
||
//
|
||
// If the peek request failed, set an error status in the response
|
||
// header.
|
||
//
|
||
|
||
status = WorkContext->Irp->IoStatus.Status;
|
||
|
||
if ( status == STATUS_BUFFER_OVERFLOW ) {
|
||
|
||
//
|
||
// Down level clients, expect us to return STATUS_SUCCESS.
|
||
//
|
||
|
||
if ( !IS_NT_DIALECT( WorkContext->Connection->SmbDialect ) ) {
|
||
status = STATUS_SUCCESS;
|
||
|
||
} else {
|
||
|
||
//
|
||
// The buffer we supplied is not big enough. Set the
|
||
// error fields in the SMB, but continue so that we send
|
||
// all the information.
|
||
//
|
||
|
||
SrvSetSmbError2( WorkContext, STATUS_BUFFER_OVERFLOW, TRUE );
|
||
|
||
}
|
||
|
||
} else if ( !NT_SUCCESS(status) ) {
|
||
|
||
IF_DEBUG(ERRORS) SrvPrint1( "Pipe peek failed: %X\n", status );
|
||
|
||
SrvSetSmbError( WorkContext, status );
|
||
SrvCompleteExecuteTransaction(
|
||
WorkContext,
|
||
SmbTransStatusErrorWithoutData
|
||
);
|
||
IF_DEBUG(TRACE2) SrvPrint0( "RestartPeekNamedPipe complete\n" );
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Success. Generate and send the response.
|
||
//
|
||
// The parameter bytes are currently in the format returned by NT.
|
||
// we will reformat them, and leave the extra space between the
|
||
// parameter and data bytes as extra pad.
|
||
//
|
||
|
||
//
|
||
// Since the NT and SMB formats overlap
|
||
// First read all the parameters into locals...
|
||
//
|
||
|
||
transaction = WorkContext->Parameters.Transaction;
|
||
pipePeekBuffer = (PFILE_PIPE_PEEK_BUFFER)transaction->OutParameters;
|
||
|
||
readDataAvailable = (USHORT)pipePeekBuffer->ReadDataAvailable;
|
||
messageLength = (USHORT)pipePeekBuffer->MessageLength;
|
||
namedPipeState = (USHORT)pipePeekBuffer->NamedPipeState;
|
||
|
||
//
|
||
// ... then copy them back in the new format.
|
||
//
|
||
|
||
respPeekNmPipe = (PRESP_PEEK_NMPIPE)pipePeekBuffer;
|
||
SmbPutAlignedUshort(
|
||
&respPeekNmPipe->ReadDataAvailable,
|
||
readDataAvailable
|
||
);
|
||
SmbPutAlignedUshort(
|
||
&respPeekNmPipe->MessageLength,
|
||
messageLength
|
||
);
|
||
SmbPutAlignedUshort(
|
||
&respPeekNmPipe->NamedPipeState,
|
||
namedPipeState
|
||
);
|
||
|
||
//
|
||
// Send the response. Set the output counts.
|
||
//
|
||
// NT return to us 4 ULONGS of parameter bytes, followed by data.
|
||
// We return to the client 6 parameter bytes.
|
||
//
|
||
|
||
transaction->SetupCount = 0;
|
||
transaction->ParameterCount = 6;
|
||
transaction->DataCount = (ULONG)WorkContext->Irp->IoStatus.Information -
|
||
(4 * sizeof(ULONG));
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
SrvCompleteExecuteTransaction(WorkContext, SmbTransStatusSuccess);
|
||
} else {
|
||
SrvCompleteExecuteTransaction(WorkContext, SmbTransStatusErrorWithData);
|
||
}
|
||
IF_DEBUG(TRACE2) SrvPrint0( "RestartPeekNamedPipe complete\n" );
|
||
return;
|
||
|
||
} // RestartPeekNamedPipe
|
||
|
||
|
||
VOID SRVFASTCALL
|
||
RestartTransactNamedPipe (
|
||
IN OUT PWORK_CONTEXT WorkContext
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the completion routine for SrvTransactNamedPipe
|
||
|
||
Arguments:
|
||
|
||
WorkContext - A pointer to a WORK_CONTEXT block.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS status;
|
||
PTRANSACTION transaction;
|
||
|
||
PAGED_CODE( );
|
||
|
||
//
|
||
// If the transceive request failed, set an error status in the response
|
||
// header.
|
||
//
|
||
|
||
status = WorkContext->Irp->IoStatus.Status;
|
||
|
||
if ( status == STATUS_BUFFER_OVERFLOW ) {
|
||
|
||
#if 0
|
||
//
|
||
// Down level clients, expect us to return STATUS_SUCCESS.
|
||
//
|
||
|
||
if ( !IS_NT_DIALECT( WorkContext->Connection->SmbDialect ) ) {
|
||
status = STATUS_SUCCESS;
|
||
|
||
} else {
|
||
|
||
//
|
||
// The buffer we supplied is not big enough. Set the
|
||
// error fields in the SMB, but continue so that we send
|
||
// all the information.
|
||
//
|
||
|
||
SrvSetSmbError2( WorkContext, STATUS_BUFFER_OVERFLOW, TRUE );
|
||
|
||
}
|
||
#else
|
||
|
||
//
|
||
// os/2 returns ERROR_MORE_DATA in this case, why we convert
|
||
// this to NO_ERROR is a mystery.
|
||
//
|
||
|
||
SrvSetSmbError2( WorkContext, STATUS_BUFFER_OVERFLOW, TRUE );
|
||
#endif
|
||
|
||
} else if ( !NT_SUCCESS(status) ) {
|
||
|
||
IF_DEBUG(ERRORS) SrvPrint1( "Pipe transceive failed: %X\n", status );
|
||
|
||
SrvSetSmbError(WorkContext, status);
|
||
SrvCompleteExecuteTransaction(
|
||
WorkContext,
|
||
SmbTransStatusErrorWithoutData
|
||
);
|
||
IF_DEBUG(TRACE2) SrvPrint0( "RestartTransactNamedPipe complete\n" );
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Success. Generate and send the response.
|
||
//
|
||
|
||
transaction = WorkContext->Parameters.Transaction;
|
||
|
||
transaction->SetupCount = 0;
|
||
transaction->ParameterCount = 0;
|
||
transaction->DataCount = (ULONG)WorkContext->Irp->IoStatus.Information;
|
||
|
||
if ( NT_SUCCESS(status) ) {
|
||
SrvCompleteExecuteTransaction(WorkContext, SmbTransStatusSuccess);
|
||
} else {
|
||
SrvCompleteExecuteTransaction(WorkContext, SmbTransStatusErrorWithData);
|
||
}
|
||
|
||
IF_DEBUG(TRACE2) SrvPrint0( "RestartTransactNamedPipe complete\n" );
|
||
return;
|
||
|
||
} // RestartTransactNamedpipe
|
||
|
||
|
||
NTSTATUS
|
||
RestartFastTransactNamedPipe (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN OUT PWORK_CONTEXT WorkContext
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the completion routine for SrvFastTransactNamedPipe
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - Pointer to target device object for the request.
|
||
|
||
Irp - Pointer to I/O request packet
|
||
|
||
WorkContext - A pointer to a WORK_CONTEXT block.
|
||
|
||
Return Value:
|
||
|
||
STATUS_MORE_PROCESSING_REQUIRED.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS status;
|
||
PSMB_HEADER header;
|
||
PRESP_TRANSACTION response;
|
||
|
||
PSMB_USHORT byteCountPtr;
|
||
PCHAR paramPtr;
|
||
CLONG paramOffset;
|
||
PCHAR dataPtr;
|
||
CLONG dataOffset;
|
||
CLONG dataLength;
|
||
CLONG sendLength;
|
||
|
||
UNLOCKABLE_CODE( 8FIL );
|
||
|
||
//
|
||
// Reset the IRP cancelled bit.
|
||
//
|
||
|
||
Irp->Cancel = FALSE;
|
||
|
||
//
|
||
// If the transceive request failed, set an error status in the response
|
||
// header.
|
||
//
|
||
|
||
status = WorkContext->Irp->IoStatus.Status;
|
||
|
||
if ( status == STATUS_BUFFER_OVERFLOW ) {
|
||
|
||
//
|
||
// os/2 returns ERROR_MORE_DATA in this case, why we convert
|
||
// this to NO_ERROR is a mystery.
|
||
//
|
||
|
||
SrvSetBufferOverflowError( WorkContext );
|
||
|
||
} else if ( !NT_SUCCESS(status) ) {
|
||
|
||
IF_DEBUG(ERRORS) SrvPrint1( "Pipe transceive failed: %X\n", status );
|
||
|
||
if ( KeGetCurrentIrql() >= DISPATCH_LEVEL ) {
|
||
WorkContext->FspRestartRoutine = RestartFastTransactNamedPipe2;
|
||
QUEUE_WORK_TO_FSP( WorkContext );
|
||
return STATUS_MORE_PROCESSING_REQUIRED;
|
||
}
|
||
|
||
RestartFastTransactNamedPipe2( WorkContext );
|
||
goto error_no_data;
|
||
}
|
||
|
||
//
|
||
// Success. Generate and send the response.
|
||
//
|
||
|
||
dataLength = (CLONG)WorkContext->Irp->IoStatus.Information;
|
||
|
||
header = WorkContext->ResponseHeader;
|
||
|
||
//
|
||
// Save a pointer to the byte count field.
|
||
//
|
||
// If the output data and parameters are not already in the SMB
|
||
// buffer we must calculate how much of the parameters and data can
|
||
// be sent in this response. The maximum amount we can send is
|
||
// minimum of the size of our buffer and the size of the client's
|
||
// buffer.
|
||
//
|
||
// The parameter and data byte blocks are aligned on longword
|
||
// boundaries in the message.
|
||
//
|
||
|
||
byteCountPtr = WorkContext->Parameters.FastTransactNamedPipe.OutSetup;
|
||
|
||
//
|
||
// The data and paramter are already in the SMB buffer. The entire
|
||
// response will fit in one response buffer and there is no copying
|
||
// to do.
|
||
//
|
||
|
||
paramPtr = WorkContext->Parameters.FastTransactNamedPipe.OutParam;
|
||
paramOffset = (CLONG)(paramPtr - (PCHAR)header);
|
||
|
||
dataPtr = WorkContext->Parameters.FastTransactNamedPipe.OutData;
|
||
dataOffset = (CLONG)(dataPtr - (PCHAR)header);
|
||
|
||
//
|
||
// The client wants a response. Build the first (and possibly only)
|
||
// response. The last received SMB of the transaction request was
|
||
// retained for this purpose.
|
||
//
|
||
|
||
response = (PRESP_TRANSACTION)WorkContext->ResponseParameters;
|
||
|
||
//
|
||
// Build the parameters portion of the response.
|
||
//
|
||
|
||
response->WordCount = (UCHAR)10;
|
||
SmbPutUshort( &response->TotalParameterCount,
|
||
(USHORT)0
|
||
);
|
||
SmbPutUshort( &response->TotalDataCount,
|
||
(USHORT)dataLength
|
||
);
|
||
SmbPutUshort( &response->Reserved, 0 );
|
||
response->SetupCount = (UCHAR)0;
|
||
response->Reserved2 = 0;
|
||
|
||
//
|
||
// We need to be sure we're not sending uninitialized kernel memory
|
||
// back to the client with the response, so zero out the range between
|
||
// byteCountPtr and dataPtr.
|
||
//
|
||
|
||
RtlZeroMemory(byteCountPtr,(ULONG)(dataPtr - (PCHAR)byteCountPtr));
|
||
|
||
//
|
||
// Finish filling in the response parameters.
|
||
//
|
||
|
||
SmbPutUshort( &response->ParameterCount, (USHORT)0 );
|
||
SmbPutUshort( &response->ParameterOffset, (USHORT)paramOffset );
|
||
SmbPutUshort( &response->ParameterDisplacement, 0 );
|
||
|
||
SmbPutUshort( &response->DataCount, (USHORT)dataLength );
|
||
SmbPutUshort( &response->DataOffset, (USHORT)dataOffset );
|
||
SmbPutUshort( &response->DataDisplacement, 0 );
|
||
|
||
SmbPutUshort(
|
||
byteCountPtr,
|
||
(USHORT)(dataPtr - (PCHAR)(byteCountPtr + 1) + dataLength)
|
||
);
|
||
|
||
//
|
||
// Calculate the length of the response message.
|
||
//
|
||
|
||
sendLength = (CLONG)( dataPtr + dataLength -
|
||
(PCHAR)WorkContext->ResponseHeader );
|
||
|
||
WorkContext->ResponseBuffer->DataLength = sendLength;
|
||
|
||
//
|
||
// Set the bit in the SMB that indicates this is a response from the
|
||
// server.
|
||
//
|
||
|
||
WorkContext->ResponseHeader->Flags |= SMB_FLAGS_SERVER_TO_REDIR;
|
||
|
||
//
|
||
// Send the response.
|
||
//
|
||
|
||
SRV_START_SEND_2(
|
||
WorkContext,
|
||
SrvFsdRestartSmbAtSendCompletion,
|
||
NULL,
|
||
NULL
|
||
);
|
||
|
||
error_no_data:
|
||
|
||
//
|
||
// The response send is in progress. The caller will assume
|
||
// the we will handle send completion.
|
||
//
|
||
// Return STATUS_MORE_PROCESSING_REQUIRED so that IoCompleteRequest
|
||
// will stop working on the IRP.
|
||
//
|
||
|
||
IF_DEBUG(TRACE2) SrvPrint0( "RestartTransactNamedPipe complete\n" );
|
||
return STATUS_MORE_PROCESSING_REQUIRED;
|
||
|
||
} // RestartFastTransactNamedPipe
|
||
|
||
|
||
VOID SRVFASTCALL
|
||
RestartFastTransactNamedPipe2 (
|
||
IN OUT PWORK_CONTEXT WorkContext
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the completion routine for SrvFastTransactNamedPipe
|
||
|
||
Arguments:
|
||
|
||
WorkContext - A pointer to a WORK_CONTEXT block.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PAGED_CODE( );
|
||
|
||
//
|
||
// The transceive request failed. Set an error status in the response
|
||
// header.
|
||
//
|
||
|
||
SrvSetSmbError( WorkContext, WorkContext->Irp->IoStatus.Status );
|
||
|
||
//
|
||
// An error occurred, so no transaction-specific response data
|
||
// will be returned.
|
||
//
|
||
// Calculate the length of the response message.
|
||
//
|
||
|
||
|
||
WorkContext->ResponseBuffer->DataLength =
|
||
(CLONG)( (PCHAR)WorkContext->ResponseParameters -
|
||
(PCHAR)WorkContext->ResponseHeader );
|
||
|
||
//
|
||
// Send the response.
|
||
//
|
||
|
||
SRV_START_SEND_2(
|
||
WorkContext,
|
||
SrvFsdRestartSmbAtSendCompletion,
|
||
NULL,
|
||
NULL
|
||
);
|
||
|
||
return;
|
||
|
||
} // RestartFastTransactNamedPipe2
|
||
|
||
|
||
VOID SRVFASTCALL
|
||
RestartRawWriteNamedPipe (
|
||
IN OUT PWORK_CONTEXT WorkContext
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the completion routine for SrvRawWriteNamedPipe
|
||
|
||
Arguments:
|
||
|
||
WorkContext - A pointer to a WORK_CONTEXT block.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS status;
|
||
PTRANSACTION transaction;
|
||
|
||
PAGED_CODE( );
|
||
|
||
//
|
||
// If the write request failed, set an error status in the response
|
||
// header.
|
||
//
|
||
|
||
status = WorkContext->Irp->IoStatus.Status;
|
||
|
||
if ( !NT_SUCCESS(status) ) {
|
||
|
||
IF_DEBUG(ERRORS) SrvPrint1( "Pipe raw write failed: %X\n", status );
|
||
|
||
SrvSetSmbError( WorkContext, status );
|
||
SrvCompleteExecuteTransaction(
|
||
WorkContext,
|
||
SmbTransStatusErrorWithoutData
|
||
);
|
||
IF_DEBUG(TRACE2) SrvPrint0( "RestartRawWriteNamedPipe complete\n" );
|
||
return;
|
||
|
||
}
|
||
|
||
//
|
||
// Success. Generate and send the response.
|
||
//
|
||
|
||
transaction = WorkContext->Parameters.Transaction;
|
||
|
||
transaction->SetupCount = 0;
|
||
transaction->ParameterCount = 2;
|
||
transaction->DataCount = 0;
|
||
|
||
SmbPutUshort( (PSMB_USHORT)transaction->OutParameters, 2 );
|
||
|
||
SrvCompleteExecuteTransaction(WorkContext, SmbTransStatusSuccess);
|
||
|
||
IF_DEBUG(TRACE2) SrvPrint0( "RestartRawWriteNamedPipe complete\n" );
|
||
return;
|
||
|
||
} // RestartRawWriteNamedpipe
|
||
|
||
|
||
SMB_TRANS_STATUS
|
||
SrvWriteNamedPipe (
|
||
IN OUT PWORK_CONTEXT WorkContext
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function handles the raw write named pipe transaction SMB.
|
||
The call to NPFS is issued asynchronously and is completed by
|
||
RestartRawWriteNamedPipe().
|
||
|
||
Arguments:
|
||
|
||
WorkContext - A pointer to a WORK_CONTEXT block.
|
||
|
||
Return Value:
|
||
|
||
SMB_TRANS_STATUS - Indicates whether an error occurred. See
|
||
smbtypes.h for a more complete description.
|
||
|
||
--*/
|
||
|
||
{
|
||
PTRANSACTION transaction;
|
||
USHORT fid;
|
||
PRFCB rfcb;
|
||
PLFCB lfcb;
|
||
NTSTATUS status;
|
||
LARGE_INTEGER offset;
|
||
ULONG key = 0;
|
||
PCHAR writeAddress;
|
||
CLONG writeLength;
|
||
|
||
PAGED_CODE( );
|
||
|
||
transaction = WorkContext->Parameters.Transaction;
|
||
|
||
//
|
||
// Get the FID from the second setup word and use it to generate a
|
||
// pointer to the RFCB.
|
||
//
|
||
// SrvVerifyFid will fill in WorkContext->Rfcb.
|
||
//
|
||
|
||
fid = SmbGetUshort( &transaction->InSetup[1] );
|
||
|
||
IF_DEBUG(IPX_PIPES) {
|
||
KdPrint(("SrvWriteNamedPipe: fid = %x length = %d\n",
|
||
fid, transaction->DataCount));
|
||
}
|
||
|
||
rfcb = SrvVerifyFid(
|
||
WorkContext,
|
||
fid,
|
||
FALSE,
|
||
SrvRestartExecuteTransaction, // serialize with raw write
|
||
&status
|
||
);
|
||
|
||
if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
|
||
|
||
if ( !NT_SUCCESS( status ) ) {
|
||
|
||
//
|
||
// Invalid file ID. Reject the request.
|
||
//
|
||
|
||
IF_DEBUG(SMB_ERRORS) {
|
||
SrvPrint1( "SrvWriteNamedPipe: Invalid FID: 0x%lx\n",
|
||
fid );
|
||
}
|
||
|
||
SrvSetSmbError( WorkContext, STATUS_INVALID_HANDLE );
|
||
IF_DEBUG(TRACE2) SrvPrint0( "SrvWriteNamedPipe complete\n" );
|
||
return SmbTransStatusErrorWithoutData;
|
||
|
||
}
|
||
|
||
//
|
||
// The work item has been queued because a raw write is in
|
||
// progress.
|
||
//
|
||
|
||
return SmbTransStatusInProgress;
|
||
|
||
}
|
||
|
||
lfcb = rfcb->Lfcb;
|
||
writeLength = transaction->DataCount;
|
||
writeAddress = transaction->InData;
|
||
|
||
//
|
||
// Try the fast I/O path first. If that fails, fall through to the
|
||
// normal build-an-IRP path.
|
||
//
|
||
|
||
if ( lfcb->FastIoWrite != NULL ) {
|
||
|
||
INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastWritesAttempted );
|
||
|
||
try {
|
||
if ( lfcb->FastIoWrite(
|
||
lfcb->FileObject,
|
||
&offset,
|
||
writeLength,
|
||
TRUE,
|
||
key,
|
||
writeAddress,
|
||
&WorkContext->Irp->IoStatus,
|
||
lfcb->DeviceObject
|
||
) ) {
|
||
|
||
//
|
||
// The fast I/O path worked. Call the restart routine directly
|
||
// to do postprocessing (including sending the response).
|
||
//
|
||
|
||
RestartWriteNamedPipe( WorkContext );
|
||
|
||
IF_DEBUG(IPX_PIPES) SrvPrint0( "SrvWriteNamedPipe complete.\n" );
|
||
return SmbTransStatusInProgress;
|
||
}
|
||
}
|
||
except( EXCEPTION_EXECUTE_HANDLER ) {
|
||
// Fall through to the slow path on an exception
|
||
NTSTATUS status = GetExceptionCode();
|
||
IF_DEBUG(ERRORS) {
|
||
KdPrint(("FastIoRead threw exception %x\n", status ));
|
||
}
|
||
}
|
||
|
||
INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastWritesFailed );
|
||
|
||
}
|
||
|
||
IF_DEBUG(IPX_PIPES) {
|
||
KdPrint(("SrvWriteNamedPipe: Using slow path.\n"));
|
||
}
|
||
|
||
//
|
||
// The turbo path failed. Build the write request, reusing the
|
||
// receive IRP.
|
||
//
|
||
// Build the PIPE_INTERNAL_WRITE IRP.
|
||
//
|
||
|
||
SrvBuildIoControlRequest(
|
||
WorkContext->Irp,
|
||
lfcb->FileObject,
|
||
WorkContext,
|
||
IRP_MJ_FILE_SYSTEM_CONTROL,
|
||
FSCTL_PIPE_INTERNAL_WRITE,
|
||
writeAddress,
|
||
writeLength,
|
||
NULL,
|
||
0,
|
||
NULL,
|
||
NULL
|
||
);
|
||
|
||
//
|
||
// Pass the request to the file system.
|
||
//
|
||
|
||
WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
|
||
WorkContext->FspRestartRoutine = RestartWriteNamedPipe;
|
||
|
||
(VOID)IoCallDriver( lfcb->DeviceObject, WorkContext->Irp );
|
||
|
||
//
|
||
// The write has been started. Control will return to
|
||
// RestartWriteNamedPipe when the write completes.
|
||
//
|
||
|
||
IF_DEBUG(TRACE2) SrvPrint0( "SrvWriteNamedPipe complete\n" );
|
||
return SmbTransStatusInProgress;
|
||
|
||
} // SrvWriteNamedPipe
|
||
|
||
VOID SRVFASTCALL
|
||
RestartWriteNamedPipe (
|
||
IN OUT PWORK_CONTEXT WorkContext
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the completion routine for SrvRawWriteNamedPipe
|
||
|
||
Arguments:
|
||
|
||
WorkContext - A pointer to a WORK_CONTEXT block.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS status;
|
||
PIO_STATUS_BLOCK iosb;
|
||
PTRANSACTION transaction;
|
||
|
||
PAGED_CODE( );
|
||
|
||
//
|
||
// If the write request failed, set an error status in the response
|
||
// header.
|
||
//
|
||
|
||
iosb = &WorkContext->Irp->IoStatus;
|
||
status = iosb->Status;
|
||
|
||
IF_DEBUG(IPX_PIPES) {
|
||
KdPrint(("RestartWriteNamedPipe: Status = %x\n", status));
|
||
}
|
||
|
||
if ( !NT_SUCCESS(status) ) {
|
||
|
||
IF_DEBUG(ERRORS) SrvPrint1( " pipe write failed: %X\n", status );
|
||
|
||
SrvSetSmbError( WorkContext, status );
|
||
SrvCompleteExecuteTransaction(
|
||
WorkContext,
|
||
SmbTransStatusErrorWithoutData
|
||
);
|
||
IF_DEBUG(TRACE2) SrvPrint0( "RestartWriteNamedPipe complete\n" );
|
||
return;
|
||
|
||
}
|
||
|
||
//
|
||
// Success. Generate and send the response.
|
||
//
|
||
|
||
transaction = WorkContext->Parameters.Transaction;
|
||
|
||
transaction->SetupCount = 0;
|
||
transaction->ParameterCount = 2;
|
||
transaction->DataCount = 0;
|
||
|
||
SmbPutUshort( (PSMB_USHORT)transaction->OutParameters,
|
||
(USHORT)iosb->Information
|
||
);
|
||
|
||
SrvCompleteExecuteTransaction(WorkContext, SmbTransStatusSuccess);
|
||
|
||
IF_DEBUG(TRACE2) SrvPrint0( "RestartWriteNamedPipe complete\n" );
|
||
return;
|
||
|
||
} // RestartWriteNamedPipe
|
||
|
||
SMB_TRANS_STATUS
|
||
SrvReadNamedPipe (
|
||
IN OUT PWORK_CONTEXT WorkContext
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function handles the raw Read named pipe transaction SMB.
|
||
The call to NPFS is issued asynchronously and is completed by
|
||
RestartRawReadNamedPipe().
|
||
|
||
Arguments:
|
||
|
||
WorkContext - A pointer to a WORK_CONTEXT block.
|
||
|
||
Return Value:
|
||
|
||
SMB_TRANS_STATUS - Indicates whether an error occurred. See
|
||
smbtypes.h for a more complete description.
|
||
|
||
--*/
|
||
|
||
{
|
||
PTRANSACTION transaction;
|
||
USHORT fid;
|
||
PRFCB rfcb;
|
||
PLFCB lfcb;
|
||
NTSTATUS status;
|
||
LARGE_INTEGER offset;
|
||
ULONG key = 0;
|
||
PCHAR readAddress;
|
||
CLONG readLength;
|
||
|
||
PAGED_CODE( );
|
||
|
||
transaction = WorkContext->Parameters.Transaction;
|
||
|
||
//
|
||
// Get the FID from the second setup word and use it to generate a
|
||
// pointer to the RFCB.
|
||
//
|
||
// SrvVerifyFid will fill in WorkContext->Rfcb.
|
||
//
|
||
|
||
fid = SmbGetUshort( &transaction->InSetup[1] );
|
||
|
||
IF_DEBUG(IPX_PIPES) {
|
||
KdPrint(("SrvReadNamedPipe: fid = %x length = %d\n",
|
||
fid, transaction->MaxDataCount));
|
||
}
|
||
|
||
rfcb = SrvVerifyFid(
|
||
WorkContext,
|
||
fid,
|
||
FALSE,
|
||
SrvRestartExecuteTransaction, // serialize with raw Read
|
||
&status
|
||
);
|
||
|
||
if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
|
||
|
||
if ( !NT_SUCCESS( status ) ) {
|
||
|
||
//
|
||
// Invalid file ID. Reject the request.
|
||
//
|
||
|
||
IF_DEBUG(SMB_ERRORS) {
|
||
SrvPrint1( "SrvReadNamedPipe: Invalid FID: 0x%lx\n",
|
||
fid );
|
||
}
|
||
|
||
SrvSetSmbError( WorkContext, STATUS_INVALID_HANDLE );
|
||
IF_DEBUG(TRACE2) SrvPrint0( "SrvReadNamedPipe complete\n" );
|
||
return SmbTransStatusErrorWithoutData;
|
||
|
||
}
|
||
|
||
//
|
||
// The work item has been queued because a raw Read is in
|
||
// progress.
|
||
//
|
||
|
||
return SmbTransStatusInProgress;
|
||
|
||
}
|
||
|
||
lfcb = rfcb->Lfcb;
|
||
readLength = transaction->MaxDataCount;
|
||
readAddress = transaction->OutData;
|
||
|
||
//
|
||
// Try the fast I/O path first. If that fails, fall through to the
|
||
// normal build-an-IRP path.
|
||
//
|
||
|
||
if ( lfcb->FastIoRead != NULL ) {
|
||
|
||
INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastReadsAttempted );
|
||
|
||
try {
|
||
if ( lfcb->FastIoRead(
|
||
lfcb->FileObject,
|
||
&offset,
|
||
readLength,
|
||
TRUE,
|
||
key,
|
||
readAddress,
|
||
&WorkContext->Irp->IoStatus,
|
||
lfcb->DeviceObject
|
||
) ) {
|
||
|
||
//
|
||
// The fast I/O path worked. Call the restart routine directly
|
||
// to do postprocessing (including sending the response).
|
||
//
|
||
|
||
RestartReadNamedPipe( WorkContext );
|
||
|
||
IF_SMB_DEBUG(READ_WRITE2) SrvPrint0( "SrvReadNamedPipe complete.\n" );
|
||
return SmbTransStatusInProgress;
|
||
}
|
||
}
|
||
except( EXCEPTION_EXECUTE_HANDLER ) {
|
||
// Fall through to the slow path on an exception
|
||
NTSTATUS status = GetExceptionCode();
|
||
IF_DEBUG(ERRORS) {
|
||
KdPrint(("FastIoRead threw exception %x\n", status ));
|
||
}
|
||
}
|
||
|
||
INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastReadsFailed );
|
||
|
||
}
|
||
|
||
//
|
||
// The turbo path failed. Build the Read request, reusing the
|
||
// receive IRP.
|
||
//
|
||
// Build the PIPE_INTERNAL_READ IRP.
|
||
//
|
||
|
||
SrvBuildIoControlRequest(
|
||
WorkContext->Irp,
|
||
lfcb->FileObject,
|
||
WorkContext,
|
||
IRP_MJ_FILE_SYSTEM_CONTROL,
|
||
FSCTL_PIPE_INTERNAL_READ,
|
||
readAddress,
|
||
0,
|
||
NULL,
|
||
readLength,
|
||
NULL,
|
||
NULL
|
||
);
|
||
|
||
//
|
||
// Pass the request to the file system.
|
||
//
|
||
|
||
WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
|
||
WorkContext->FspRestartRoutine = RestartReadNamedPipe;
|
||
|
||
(VOID)IoCallDriver( lfcb->DeviceObject, WorkContext->Irp );
|
||
|
||
//
|
||
// The Read has been started. Control will return to
|
||
// SrvFsdRestartRead when the Read completes.
|
||
//
|
||
|
||
IF_DEBUG(TRACE2) SrvPrint0( "SrvReadNamedPipe complete\n" );
|
||
return SmbTransStatusInProgress;
|
||
|
||
} // SrvReadNamedPipe
|
||
|
||
|
||
VOID SRVFASTCALL
|
||
RestartReadNamedPipe (
|
||
IN OUT PWORK_CONTEXT WorkContext
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the completion routine for SrvRawReadNamedPipe
|
||
|
||
Arguments:
|
||
|
||
WorkContext - A pointer to a WORK_CONTEXT block.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS status;
|
||
PTRANSACTION transaction;
|
||
|
||
PAGED_CODE( );
|
||
|
||
//
|
||
// If the transceive request failed, set an error status in the response
|
||
// header.
|
||
//
|
||
|
||
status = WorkContext->Irp->IoStatus.Status;
|
||
|
||
if ( status == STATUS_BUFFER_OVERFLOW ) {
|
||
|
||
SrvSetSmbError2( WorkContext, STATUS_BUFFER_OVERFLOW, TRUE );
|
||
|
||
} else if ( !NT_SUCCESS(status) ) {
|
||
|
||
IF_DEBUG(ERRORS) SrvPrint1( "Pipe transceive failed: %X\n", status );
|
||
|
||
SrvSetSmbError(WorkContext, status);
|
||
SrvCompleteExecuteTransaction(
|
||
WorkContext,
|
||
SmbTransStatusErrorWithoutData
|
||
);
|
||
IF_DEBUG(TRACE2) SrvPrint0( "RestartReadNamedPipe complete\n" );
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Success. Generate and send the response.
|
||
//
|
||
|
||
transaction = WorkContext->Parameters.Transaction;
|
||
|
||
transaction->SetupCount = 0;
|
||
transaction->ParameterCount = 0;
|
||
transaction->DataCount = (ULONG)WorkContext->Irp->IoStatus.Information;
|
||
|
||
if ( NT_SUCCESS(status) ) {
|
||
SrvCompleteExecuteTransaction(WorkContext, SmbTransStatusSuccess);
|
||
} else {
|
||
SrvCompleteExecuteTransaction(WorkContext, SmbTransStatusErrorWithData);
|
||
}
|
||
|
||
IF_DEBUG(TRACE2) SrvPrint0( "RestartReadNamedPipe complete\n" );
|
||
return;
|
||
|
||
} // RestartReadNamedPipe
|