|
|
/*++
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
|