383 lines
10 KiB
C
383 lines
10 KiB
C
/*++
|
||
|
||
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
|
||
|