/*++ Copyright (c) 1991 Microsoft Corporation Module Name: svccdev.c Abstract: This module contains routines for supporting the character device APIs in the server service, SrvNetCharDevControl, SrvNetCharDevEnum, and SrvNetCharDevGetInfo. Author: David Treadwell (davidtr) 31-Jan-1991 Revision History: --*/ #include "precomp.h" #pragma hdrstop #ifdef ALLOC_PRAGMA #if !SRV_COMM_DEVICES #pragma alloc_text( PAGE, SrvNetCharDevControl ) #endif #pragma alloc_text( PAGE, SrvNetCharDevEnum ) #if SRV_COMM_DEVICES #pragma alloc_text( PAGE, FillCharDevInfoBuffer ) #pragma alloc_text( PAGE, FilterCharDevs ) #pragma alloc_text( PAGE, SizeCharDevs ) #endif #endif #if 0 #if SRV_COMM_DEVICES NOT PAGEABLE -- SrvNetCharDevControl #endif #endif // // Forward declarations. // VOID FillCharDevInfoBuffer ( IN PSERVER_REQUEST_PACKET Srp, IN PVOID Block, IN OUT PVOID *FixedStructure, IN LPTSTR *EndOfVariableData ); BOOLEAN FilterCharDevs ( IN PSERVER_REQUEST_PACKET Srp, IN PVOID Block ); ULONG SizeCharDevs ( IN PSERVER_REQUEST_PACKET Srp, IN PVOID Block ); // // Macros to determine the size a character device would take up at one of the // levels of chardev information. // #define TOTAL_SIZE_OF_CHARDEV(level,commDevice) \ ( (level) == 0 ? sizeof(CHARDEV_INFO_0) + \ SrvLengthOfStringInApiBuffer(&(commDevice)->DosPathName) :\ sizeof(CHARDEV_INFO_1) + \ SrvLengthOfStringInApiBuffer(&(commDevice)->DosPathName) +\ ( (commDevice)->Rfcb == NULL ? 0 : \ SrvLengthOfStringInApiBuffer( \ &(commDevice)->Rfcb->Lfcb->Session->UserName) ) ) #define FIXED_SIZE_OF_CHARDEV(level) \ ( (level) == 0 ? sizeof(CHARDEV_INFO_0) : \ sizeof(CHARDEV_INFO_1) ) NTSTATUS SrvNetCharDevControl ( IN PSERVER_REQUEST_PACKET Srp, IN PVOID Buffer, IN ULONG BufferLength ) /*++ Routine Description: This routine processes the NetCharDevControl API in the server FSP. It must run in the FSP in order to close the file handle of the open, in any. Arguments: Srp - a pointer to the server request packet that contains all the information necessary to satisfy the request. This includes: INPUT: Name1 - DOS name of the comm device to close (e.g. "COM1:"). OUTPUT: None. Buffer - unused. BufferLength - unused. Return Value: NTSTATUS - result of operation to return to the server service. --*/ { #if SRV_COMM_DEVICES BOOLEAN foundCharDev = FALSE; BOOLEAN closedCharDev = FALSE; PCOMM_DEVICE commDevice; KIRQL oldIrql; Buffer, BufferLength; // // Walk the ordered list, to find the device specified in Srp->Name1. // If we find it and it is open, close it. // if ( ( commDevice = SrvFindEntryInOrderedList( &SrvCommDeviceList, (PFILTER_ROUTINE)FilterCharDevs, Srp, (ULONG)-1, FALSE, NULL ) ) != NULL ) { foundCharDev = TRUE; // // If the comm device is in use (i.e. opened) close the RFCB // of the open and indicate that the comm device is not open. // ACQUIRE_GLOBAL_SPIN_LOCK( Fsd, &oldIrql ); if ( commDevice->InUse ) { PRFCB rfcb = commDevice->Rfcb; commDevice->InUse = FALSE; commDevice->Rfcb = NULL; RELEASE_GLOBAL_SPIN_LOCK( Fsd, oldIrql ); // // Close the RFCB; this will result in the comm device handle // being closed. // SrvCloseRfcb( rfcb ); closedCharDev = TRUE; } else { RELEASE_GLOBAL_SPIN_LOCK( Fsd, oldIrql ); } // // SrvFindEntryInOrderedList referenced the session; dereference // it here. // SrvDereferenceCommDevice( commDevice ); } // // The API is only successful if the specified comm device is shared // and open. If one of these isn't true, return an appropriate error. // if ( foundCharDev && closedCharDev ) { return STATUS_SUCCESS; } else if ( !closedCharDev ) { Srp->ErrorCode = NERR_DevNotOpen; return STATUS_SUCCESS; } #endif // SRV_COMM_DEVICES Srp->ErrorCode = NERR_DevNotFound; return STATUS_SUCCESS; } // SrvNetCharDevControl NTSTATUS SrvNetCharDevEnum ( IN PSERVER_REQUEST_PACKET Srp, IN PVOID Buffer, IN ULONG BufferLength ) /*++ Routine Description: This routine processes the NetCharDevEnum API in the server. Arguments: Srp - a pointer to the server request packet that contains all the information necessary to satisfy the request. This includes: INPUT: Level - level of information to return, 0, or 1. OUTPUT: Parameters.Get.EntriesRead - the number of entries that fit in the output buffer. Parameters.Get.TotalEntries - the total number of entries that would be returned with a large enough buffer. Parameters.Get.TotalBytesNeeded - the buffer size that would be required to hold all the entries. Buffer - a pointer to the buffer for results. BufferLength - the length of this buffer. Return Value: NTSTATUS - result of operation to return to the server service. --*/ { PAGED_CODE( ); #if SRV_COMM_DEVICES return SrvEnumApiHandler( Srp, Buffer, BufferLength, &SrvCommDeviceList, FilterCharDevs, SizeCharDevs, FillCharDevInfoBuffer ); #else Srp->Parameters.Get.EntriesRead = 0; Srp->Parameters.Get.TotalEntries = 0; Srp->Parameters.Get.TotalBytesNeeded = 0; Srp->ErrorCode = NO_ERROR; return STATUS_SUCCESS; #endif } // SrvNetCharDevEnum #if SRV_COMM_DEVICES VOID FillCharDevInfoBuffer ( IN PSERVER_REQUEST_PACKET Srp, IN PVOID Block, IN OUT PVOID *FixedStructure, IN LPTSTR *EndOfVariableData ) /*++ Routine Description: This routine puts a single fixed file structure and associated variable data, into a buffer. Fixed data goes at the beginning of the buffer, variable data at the end. *** This routine assumes that ALL the data, both fixed and variable, will fit. Arguments: Srp - a pointer to the SRP for the operation. Only the Level field is used. Block - the comm device from which to get information. FixedStructure - where the in the buffer to place the fixed structure. This pointer is updated to point to the next available position for a fixed structure. EndOfVariableData - the last position on the buffer that variable data for this structure can occupy. The actual variable data is written before this position as long as it won't overwrite fixed structures. It is would overwrite fixed structures, it is not written. Return Value: None. --*/ { PCHARDEV_INFO_1 ch1 = *FixedStructure; PCOMM_DEVICE commDevice = Block; LARGE_INTEGER currentTime; DWORD currentSecondsSince1980; DWORD startSecondsSince1980; DWORD secondsInUse; PAGED_CODE( ); // // Get the current time and use this to determine how long the // device has been in use. // KeQuerySystemTime( ¤tTime ); RtlTimeToSecondsSince1980( ¤tTime, ¤tSecondsSince1980 ); RtlTimeToSecondsSince1980( &commDevice->StartTime, &startSecondsSince1980 ); secondsInUse = currentSecondsSince1980 - startSecondsSince1980; // // Update FixedStructure to point to the next structure location. // *FixedStructure = (PCHAR)*FixedStructure + FIXED_SIZE_OF_CHARDEV( Srp->Level ); ASSERT( (ULONG)*EndOfVariableData >= (ULONG)*FixedStructure ); // // Case on the level to fill in the fixed structure appropriately. // We fill in actual pointers in the output structure. This is // possible because we are in the server FSD, hence the server // service's process and address space. // // *** Using the switch statement in this fashion relies on the fact // that the first fields on the different chardev structures are // identical (with the exception of level 10, which is handled // separately). // switch( Srp->Level ) { case 1: // // Copy the user name to the output buffer. // if ( commDevice->Rfcb != NULL ) { SrvCopyUnicodeStringToBuffer( &commDevice->Rfcb->Lfcb->Session->UserName, *FixedStructure, EndOfVariableData, &ch1->ch1_username ); } else { ch1->ch1_username = NULL; } // // Set up other fields. // // !!! how do we determine whether to set CHARDEV_STAT_ERROR? if ( commDevice->InUse ) { ch1->ch1_status = CHARDEV_STAT_OPENED; ch1->ch1_time = secondsInUse; } else { ch1->ch1_status = 0; ch1->ch1_time = 0; } // *** lack of break is intentional! case 0: // // Set up the device name in the output buffer. // SrvCopyUnicodeStringToBuffer( &commDevice->DosPathName, *FixedStructure, EndOfVariableData, &ch1->ch1_dev ); break; default: // // This should never happen. The server service should have // checked for an invalid level. // INTERNAL_ERROR( ERROR_LEVEL_UNEXPECTED, "FillCharDevInfoBuffer: invalid level number: %ld", Srp->Level, NULL ); SrvLogInvalidSmb( NULL ); return; } return; } // FillCharDevInfoBuffer BOOLEAN FilterCharDevs ( IN PSERVER_REQUEST_PACKET Srp, IN PVOID Block ) /*++ Routine Description: This routine is intended to be called by SrvEnumApiHandler to check whether a particular comm device should be returned. Arguments: Srp - a pointer to the SRP for the operation. Name1 is specified NetCharDevGetInfo, and if set must match the DOS path name of the device for the device to be returned. Block - a pointer to the comm device to check. Return Value: TRUE if the block should be placed in the output buffer, FALSE if it should be passed over. --*/ { PCOMM_DEVICE commDevice = Block; PAGED_CODE( ); // // If there's a device name in the SRP, it must match the // DOS path name of the device. // if ( Srp->Name1.Length > 0 ) { if ( !RtlEqualUnicodeString( &Srp->Name1, &commDevice->DosPathName, TRUE ) ) { return FALSE; } } // // We want the comm device. // return TRUE; } // FilterCharDevs ULONG SizeCharDevs ( IN PSERVER_REQUEST_PACKET Srp, IN PVOID Block ) /*++ Routine Description: This routine returns the size the passed-in comm device would take up in an API output buffer. Arguments: Srp - a pointer to the SRP for the operation. Only the level parameter is used. Block - a pointer to the comm device to size. Return Value: ULONG - The number of bytes the comm device would take up in the output buffer. --*/ { PCOMM_DEVICE commDevice = Block; PAGED_CODE( ); return TOTAL_SIZE_OF_CHARDEV( Srp->Level, commDevice ); } // SizeCharDevs #endif // SRV_COMM_DEVICES