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