You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3124 lines
80 KiB
3124 lines
80 KiB
/*++
|
|
|
|
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.
|
|
//
|
|
|
|
if( transaction->SetupCount < sizeof(USHORT)*2 )
|
|
{
|
|
SrvSetSmbError( WorkContext, STATUS_INVALID_PARAMETER );
|
|
return SmbTransStatusErrorWithoutData;
|
|
}
|
|
|
|
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);
|
|
|
|
if( transaction->MaxParameterCount < sizeof(USHORT) )
|
|
{
|
|
SrvSetSmbError( WorkContext, STATUS_INVALID_PARAMETER );
|
|
return SmbTransStatusErrorWithoutData;
|
|
}
|
|
|
|
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.
|
|
//
|
|
|
|
if( transaction->SetupCount < sizeof(USHORT)*2 )
|
|
{
|
|
SrvSetSmbError( WorkContext, STATUS_INVALID_PARAMETER );
|
|
return SmbTransStatusErrorWithoutData;
|
|
}
|
|
|
|
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.
|
|
//
|
|
|
|
if( transaction->SetupCount < sizeof(USHORT)*2 )
|
|
{
|
|
SrvSetSmbError( WorkContext, STATUS_INVALID_PARAMETER );
|
|
return SmbTransStatusErrorWithoutData;
|
|
}
|
|
|
|
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.
|
|
//
|
|
|
|
if( transaction->ParameterCount < sizeof(USHORT) )
|
|
{
|
|
SrvSetSmbError( WorkContext, STATUS_INVALID_PARAMETER );
|
|
return SmbTransStatusErrorWithoutData;
|
|
}
|
|
|
|
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.
|
|
//
|
|
|
|
if( transaction->SetupCount < sizeof(USHORT)*2 )
|
|
{
|
|
SrvSetSmbError( WorkContext, STATUS_INVALID_PARAMETER );
|
|
return SmbTransStatusErrorWithoutData;
|
|
}
|
|
|
|
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.
|
|
//
|
|
|
|
if( transaction->SetupCount < sizeof(USHORT)*2 )
|
|
{
|
|
SrvSetSmbError( WorkContext, STATUS_INVALID_PARAMETER );
|
|
return SmbTransStatusErrorWithoutData;
|
|
}
|
|
|
|
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.
|
|
//
|
|
|
|
if( transaction->SetupCount < sizeof(USHORT)*2 )
|
|
{
|
|
SrvSetSmbError( WorkContext, STATUS_INVALID_PARAMETER );
|
|
return SmbTransStatusErrorWithoutData;
|
|
}
|
|
|
|
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.
|
|
//
|
|
|
|
if( transaction->SetupCount < sizeof(USHORT)*2 )
|
|
{
|
|
SrvSetSmbError( WorkContext, STATUS_INVALID_PARAMETER );
|
|
return SmbTransStatusErrorWithoutData;
|
|
}
|
|
|
|
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
|
|
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.
|
|
//
|
|
|
|
if( transaction->SetupCount < sizeof(USHORT)*2 )
|
|
{
|
|
SrvSetSmbError( WorkContext, STATUS_INVALID_PARAMETER );
|
|
return SmbTransStatusErrorWithoutData;
|
|
}
|
|
|
|
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
|
|
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
|