Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

532 lines
12 KiB

/*++
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( &currentTime );
RtlTimeToSecondsSince1980(
&currentTime,
&currentSecondsSince1980
);
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