windows-nt/Source/XPSP1/NT/base/fs/srv/smbprint.c

383 lines
9.9 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
smbprint.c
Abstract:
This module implements printing SMB processors:
Open Print File
Close Print File
Get Print Queue
Author:
David Treadwell (davidtr) 08-Feb-1990
Revision History:
--*/
#include "precomp.h"
#include "smbprint.tmh"
#pragma hdrstop
#ifdef ALLOC_PRAGMA
#pragma alloc_text( PAGE, SrvSmbOpenPrintFile )
#pragma alloc_text( PAGE, SrvSmbGetPrintQueue )
#pragma alloc_text( PAGE, SrvSmbClosePrintFile )
#endif
SMB_PROCESSOR_RETURN_TYPE
SrvSmbOpenPrintFile (
SMB_PROCESSOR_PARAMETERS
)
/*++
Routine Description:
This routine processes the Open Print File SMB.
Arguments:
SMB_PROCESSOR_PARAMETERS - See smbtypes.h for a description
of the parameters to SMB processor routines.
Return Value:
SMB_PROCESSOR_RETURN_TYPE - See smbtypes.h
--*/
{
NTSTATUS status = STATUS_SUCCESS;
SMB_STATUS SmbStatus = SmbStatusInProgress;
PTREE_CONNECT treeConnect;
PRESP_OPEN_PRINT_FILE response;
PAGED_CODE( );
if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
WorkContext->PreviousSMB = EVENT_TYPE_SMB_OPEN_PRINT_FILE;
SrvWmiStartContext(WorkContext);
//
// Make sure we are on a blocking thread!
//
if( WorkContext->UsingBlockingThread == 0 ) {
SrvQueueWorkToBlockingThread( WorkContext );
return SmbStatusInProgress;
}
//
// Verify that this is a print share.
//
// *** We are putting in this check because some public domain Samba
// smb clients are trying to print through a disk share.
//
treeConnect = SrvVerifyTid(
WorkContext,
SmbGetAlignedUshort( &WorkContext->RequestHeader->Tid )
);
if ( treeConnect == NULL ) {
IF_DEBUG(SMB_ERRORS) {
KdPrint(( "SrvSmbPrintFile: Invalid TID.\n" ));
}
SrvSetSmbError( WorkContext, STATUS_SMB_BAD_TID );
status = STATUS_SMB_BAD_TID;
SmbStatus = SmbStatusSendResponse;
goto Cleanup;
}
//
// if it's not a print share, tell the client to get lost.
//
if ( treeConnect->Share->ShareType != ShareTypePrint ) {
SrvSetSmbError( WorkContext, STATUS_INVALID_DEVICE_REQUEST );
status = STATUS_INVALID_DEVICE_REQUEST;
SmbStatus = SmbStatusSendResponse;
goto Cleanup;
}
//
// Call SrvCreateFile to open a print spooler file. None of the
// options such as desired access, etc. are relevant for a print
// open--they are all set to default values by SrvCreateFile.
//
status = SrvCreateFile(
WorkContext,
0, // SmbDesiredAccess
0, // SmbFileAttributes
0, // SmbOpenFunction
0, // SmbAllocationSize
0, // SmbFileName
NULL, // EndOfSmbFileName
NULL, // EaBuffer
0, // EaLength
NULL, // EaErrorOffset
0, // RequestedOplockType
NULL // RestartRoutine
);
//
// There should never be an oplock on one of these special spooler
// files.
//
ASSERT( status != STATUS_OPLOCK_BREAK_IN_PROGRESS );
if ( !NT_SUCCESS(status) ) {
SrvSetSmbError( WorkContext, status );
SmbStatus = SmbStatusSendResponse;
goto Cleanup;
}
//
// Set up the response SMB.
//
response = (PRESP_OPEN_PRINT_FILE)WorkContext->ResponseParameters;
response->WordCount = 1;
SmbPutUshort( &response->Fid, WorkContext->Rfcb->Fid );
SmbPutUshort( &response->ByteCount, 0 );
WorkContext->ResponseParameters = NEXT_LOCATION(
response,
RESP_OPEN_PRINT_FILE,
0
);
SmbStatus = SmbStatusSendResponse;
Cleanup:
SrvWmiEndContext(WorkContext);
return SmbStatus;
} // SrvSmbOpenPrintFile
SMB_PROCESSOR_RETURN_TYPE
SrvSmbClosePrintFile (
SMB_PROCESSOR_PARAMETERS
)
/*++
Routine Description:
This routine processes the Close Print File SMB.
Arguments:
SMB_PROCESSOR_PARAMETERS - See smbtypes.h for a description
of the parameters to SMB processor routines.
Return Value:
SMB_PROCESSOR_RETURN_TYPE - See smbtypes.h
--*/
{
PREQ_CLOSE_PRINT_FILE request;
PRESP_CLOSE_PRINT_FILE response;
PSESSION session;
PRFCB rfcb;
NTSTATUS status = STATUS_SUCCESS;
SMB_STATUS SmbStatus = SmbStatusInProgress;
PAGED_CODE( );
if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
WorkContext->PreviousSMB = EVENT_TYPE_SMB_CLOSE_PRINT_FILE;
SrvWmiStartContext(WorkContext);
//
// Make sure we are on a blocking thread
//
if( WorkContext->UsingBlockingThread == 0 ) {
SrvQueueWorkToBlockingThread( WorkContext );
SmbStatus = SmbStatusInProgress;
goto Cleanup;
}
IF_SMB_DEBUG(OPEN_CLOSE1) {
KdPrint(( "Close print file request header at 0x%p, response header at 0x%p\n",
WorkContext->RequestHeader,
WorkContext->ResponseHeader ));
KdPrint(( "Close print file request parameters at 0x%p, response parameters at 0x%p\n",
WorkContext->RequestParameters,
WorkContext->ResponseParameters ));
}
//
// Set up parameters.
//
request = (PREQ_CLOSE_PRINT_FILE)(WorkContext->RequestParameters);
response = (PRESP_CLOSE_PRINT_FILE)(WorkContext->ResponseParameters);
//
// If a session block has not already been assigned to the current
// work context, verify the UID. If verified, the address of the
// session block corresponding to this user is stored in the
// WorkContext block and the session block is referenced.
//
session = SrvVerifyUid(
WorkContext,
SmbGetAlignedUshort( &WorkContext->RequestHeader->Uid )
);
if ( session == NULL ) {
IF_DEBUG(SMB_ERRORS) {
KdPrint(( "SrvSmbClose: Invalid UID: 0x%lx\n",
SmbGetAlignedUshort( &WorkContext->RequestHeader->Uid ) ));
}
SrvSetSmbError( WorkContext, STATUS_SMB_BAD_UID );
status = STATUS_SMB_BAD_UID;
SmbStatus = SmbStatusSendResponse;
goto Cleanup;
}
//
// First, verify the FID. If verified, the RFCB and the TreeConnect
// block are referenced and their addresses are stored in the
// WorkContext block, and the RFCB address is returned.
//
// Call SrvVerifyFid, but do not fail (return NULL) if there
// is a saved write behind error for this rfcb. The rfcb is
// needed in order to process the close.
//
rfcb = SrvVerifyFid(
WorkContext,
SmbGetUshort( &request->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) {
KdPrint(( "SrvSmbClose: Invalid FID: 0x%lx\n",
SmbGetUshort( &request->Fid ) ));
}
SrvSetSmbError( WorkContext, STATUS_INVALID_HANDLE );
status = STATUS_INVALID_HANDLE;
SmbStatus = SmbStatusSendResponse;
goto Cleanup;
}
//
// The work item has been queued because a raw write is in
// progress.
//
SmbStatus = SmbStatusInProgress;
goto Cleanup;
} else if ( !NT_SUCCESS( rfcb->SavedError ) ) {
//
// Check the saved error.
//
(VOID)SrvCheckForSavedError( WorkContext, rfcb );
}
//
// Now proceed to do the actual close file, even if there was
// a write behind error.
//
SrvCloseRfcb( rfcb );
//
// Dereference the RFCB immediately, rather than waiting for normal
// work context cleanup after the response send completes. This
// gets the xFCB structures cleaned up in a more timely manner.
//
// *** The specific motivation for this change was to fix a problem
// where a compatibility mode open was closed, the response was
// sent, and a Delete SMB was received before the send
// completion was processed. This resulted in the MFCB and LFCB
// still being present, which caused the delete processing to
// try to use the file handle in the LFCB, which we just closed
// here.
//
SrvDereferenceRfcb( rfcb );
WorkContext->Rfcb = NULL;
//
// Build the response SMB.
//
response->WordCount = 0;
SmbPutUshort( &response->ByteCount, 0 );
WorkContext->ResponseParameters = NEXT_LOCATION(
response,
RESP_CLOSE_PRINT_FILE,
0
);
SmbStatus = SmbStatusSendResponse;
Cleanup:
SrvWmiEndContext(WorkContext);
return SmbStatus;
} // SrvSmbClosePrintFile
SMB_PROCESSOR_RETURN_TYPE
SrvSmbGetPrintQueue (
SMB_PROCESSOR_PARAMETERS
)
/*++
Routine Description:
This routine processes the Get Print Queue SMB.
Arguments:
SMB_PROCESSOR_PARAMETERS - See smbtypes.h for a description
of the parameters to SMB processor routines.
Return Value:
SMB_PROCESSOR_RETURN_TYPE - See smbtypes.h
--*/
{
PAGED_CODE( );
return SrvSmbNotImplemented( SMB_PROCESSOR_ARGUMENTS );
} // SrvSmbGetPrintQueue