WindowsXP-SP1/termsrv/drivers/termdd/dispatch.c
2020-09-30 16:53:49 +02:00

724 lines
17 KiB
C

/*************************************************************************
*
* dispatch.c
*
* This module contains the dispatch routines for the TERMDD driver.
*
* Copyright 1998, Microsoft.
*
*************************************************************************/
/*
* Includes
*/
#include <precomp.h>
#pragma hdrstop
#include "ptdrvcom.h"
NTSTATUS
IcaDeviceControl (
IN PIRP Irp,
IN PIO_STACK_LOCATION IrpSp
);
NTSTATUS
IcaCreate (
IN PIRP Irp,
IN PIO_STACK_LOCATION IrpSp
);
NTSTATUS
IcaRead (
IN PIRP Irp,
IN PIO_STACK_LOCATION IrpSp
);
NTSTATUS
IcaWrite (
IN PIRP Irp,
IN PIO_STACK_LOCATION IrpSp
);
NTSTATUS
IcaWriteSync (
IN PIRP Irp,
IN PIO_STACK_LOCATION IrpSp
);
NTSTATUS
IcaCleanup (
IN PIRP Irp,
IN PIO_STACK_LOCATION IrpSp
);
NTSTATUS
IcaClose (
IN PIRP Irp,
IN PIO_STACK_LOCATION IrpSp
);
NTSTATUS
IcaDispatch (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This is the dispatch routine for ICA.
Arguments:
DeviceObject - Pointer to device object for target device
Irp - Pointer to I/O request packet
Return Value:
NTSTATUS -- Indicates whether the request was successfully queued.
--*/
{
PIO_STACK_LOCATION irpSp;
KIRQL saveIrql;
NTSTATUS Status;
irpSp = IoGetCurrentIrpStackLocation( Irp );
/*
* Fan out the IRPs based on device type
*/
if (*((ULONG *)(DeviceObject->DeviceExtension)) != DEV_TYPE_TERMDD)
{
/*
* This is for the port driver part of TermDD
*/
switch ( irpSp->MajorFunction ) {
case IRP_MJ_CREATE:
return PtCreate(DeviceObject, Irp);
case IRP_MJ_CLOSE:
return PtClose(DeviceObject, Irp);
case IRP_MJ_INTERNAL_DEVICE_CONTROL:
return PtInternalDeviceControl(DeviceObject, Irp);
case IRP_MJ_DEVICE_CONTROL:
return PtDeviceControl(DeviceObject, Irp);
case IRP_MJ_FLUSH_BUFFERS:
return STATUS_NOT_IMPLEMENTED;
case IRP_MJ_PNP:
return PtPnP(DeviceObject, Irp);
case IRP_MJ_POWER:
return PtPower(DeviceObject, Irp);
case IRP_MJ_SYSTEM_CONTROL:
return PtSystemControl(DeviceObject, Irp);
default:
KdPrint(( "IcaDispatch: Invalid major function FOR PORT DRIVER %lx\n",
irpSp->MajorFunction ));
Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
IoCompleteRequest( Irp, IcaPriorityBoost );
return STATUS_NOT_IMPLEMENTED;
}
}
else
{
switch ( irpSp->MajorFunction ) {
case IRP_MJ_WRITE:
ASSERT( FIELD_OFFSET( IO_STACK_LOCATION, Parameters.Write.Length ) ==
FIELD_OFFSET( IO_STACK_LOCATION, Parameters.DeviceIoControl.OutputBufferLength ) );
ASSERT( FIELD_OFFSET( IO_STACK_LOCATION, Parameters.Write.Key ) ==
FIELD_OFFSET( IO_STACK_LOCATION, Parameters.DeviceIoControl.InputBufferLength ) );
saveIrql = KeGetCurrentIrql();
irpSp->Parameters.Write.Key = 0;
Status = IcaWrite( Irp, irpSp );
ASSERT( KeGetCurrentIrql( ) == saveIrql );
return Status;
case IRP_MJ_READ:
ASSERT( FIELD_OFFSET( IO_STACK_LOCATION, Parameters.Read.Length ) ==
FIELD_OFFSET( IO_STACK_LOCATION, Parameters.DeviceIoControl.OutputBufferLength ) );
ASSERT( FIELD_OFFSET( IO_STACK_LOCATION, Parameters.Read.Key ) ==
FIELD_OFFSET( IO_STACK_LOCATION, Parameters.DeviceIoControl.InputBufferLength ) );
saveIrql = KeGetCurrentIrql();
irpSp->Parameters.Read.Key = 0;
Status = IcaRead( Irp, irpSp );
ASSERT( KeGetCurrentIrql( ) == saveIrql );
return Status;
case IRP_MJ_DEVICE_CONTROL:
saveIrql = KeGetCurrentIrql();
Status = IcaDeviceControl( Irp, irpSp );
ASSERT( KeGetCurrentIrql( ) == saveIrql );
Irp->IoStatus.Status = Status;
IoCompleteRequest( Irp, IcaPriorityBoost );
return( Status );
case IRP_MJ_CREATE:
Status = IcaCreate( Irp, irpSp );
ASSERT( KeGetCurrentIrql( ) == LOW_LEVEL );
Irp->IoStatus.Status = Status;
IoCompleteRequest( Irp, IcaPriorityBoost );
return Status;
case IRP_MJ_FLUSH_BUFFERS :
Status = IcaWriteSync( Irp, irpSp );
ASSERT( KeGetCurrentIrql( ) == LOW_LEVEL );
Irp->IoStatus.Status = Status;
IoCompleteRequest( Irp, IcaPriorityBoost );
return Status;
case IRP_MJ_CLEANUP:
Status = IcaCleanup( Irp, irpSp );
Irp->IoStatus.Status = Status;
IoCompleteRequest( Irp, IcaPriorityBoost );
ASSERT( KeGetCurrentIrql( ) == LOW_LEVEL );
return Status;
case IRP_MJ_CLOSE:
Status = IcaClose( Irp, irpSp );
Irp->IoStatus.Status = Status;
IoCompleteRequest( Irp, IcaPriorityBoost );
ASSERT( KeGetCurrentIrql( ) == LOW_LEVEL );
return Status;
case IRP_MJ_QUERY_SECURITY:
Status = STATUS_INVALID_DEVICE_REQUEST;
Irp->IoStatus.Status = Status;
IoCompleteRequest( Irp, IcaPriorityBoost );
return Status;
default:
Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
IoCompleteRequest( Irp, IcaPriorityBoost );
return STATUS_NOT_IMPLEMENTED;
}
}
}
BOOLEAN
IcaIsSystemProcessRequest (
PIRP Irp,
PIO_STACK_LOCATION IrpSp)
{
PACCESS_STATE accessState;
PIO_SECURITY_CONTEXT securityContext;
PACCESS_TOKEN accessToken;
PTOKEN_USER userId = NULL;
BOOLEAN result = FALSE;
NTSTATUS status = STATUS_SUCCESS;
PSID systemSid;
ASSERT(Irp != NULL);
ASSERT(IrpSp != NULL);
securityContext = IrpSp->Parameters.Create.SecurityContext;
ASSERT(securityContext != NULL);
//
// Get the well-known system SID.
//
systemSid = ExAllocatePoolWithTag(
PagedPool,
RtlLengthRequiredSid(1),
ICA_POOL_TAG
);
if (systemSid) {
SID_IDENTIFIER_AUTHORITY identifierAuthority = SECURITY_NT_AUTHORITY;
*(RtlSubAuthoritySid(systemSid, 0)) = SECURITY_LOCAL_SYSTEM_RID;
status = RtlInitializeSid(systemSid, &identifierAuthority, (UCHAR)1);
}
else {
status = STATUS_INSUFFICIENT_RESOURCES;
}
//
// Get the non-impersonated, primary token for the IRP request.
//
accessState = securityContext->AccessState;
accessToken = accessState->SubjectSecurityContext.PrimaryToken;
//
// We got the system SID. Now compare the caller's SID.
//
if (NT_SUCCESS(status) && accessToken){
//
// Get the user ID associated with the primary token for the process
// that generated the IRP.
//
status = SeQueryInformationToken(
accessToken,
TokenUser,
&userId
);
//
// Do the comparison.
//
if (NT_SUCCESS(status)) {
result = RtlEqualSid(systemSid, userId->User.Sid);
ExFreePool(userId);
}
}
if (systemSid) {
ExFreePool(systemSid);
}
return result;
}
NTSTATUS
IcaCreate (
IN PIRP Irp,
IN PIO_STACK_LOCATION IrpSp
)
/*++
Routine Description:
This is the routine that handles Create IRPs in ICA.
Arguments:
Irp - Pointer to I/O request packet.
IrpSp - pointer to the IO stack location to use for this request.
Return Value:
NTSTATUS -- Indicates whether the request was successfully queued.
--*/
{
PICA_OPEN_PACKET openPacket;
PFILE_FULL_EA_INFORMATION eaBuffer;
PFILE_OBJECT pConnectFileObject;
PICA_CONNECTION pConnect;
NTSTATUS Status;
PAGED_CODE( );
// Save result in FsContext2: if the requestor is system process or not
IrpSp->FileObject->FsContext2 = (VOID*) IcaIsSystemProcessRequest(Irp, IrpSp);
/*
* Find the open packet from the EA buffer in the system buffer of
* the associated IRP. If no EA buffer was specified, then this
* is a request to open a new ICA connection.
*/
eaBuffer = Irp->AssociatedIrp.SystemBuffer;
if ( eaBuffer == NULL ) {
return( IcaCreateConnection( Irp, IrpSp ) );
}
if (eaBuffer->EaValueLength < sizeof(ICA_OPEN_PACKET)) {
ASSERT(FALSE);
return STATUS_INVALID_PARAMETER;
}
openPacket = (PICA_OPEN_PACKET)(eaBuffer->EaName + eaBuffer->EaNameLength + 1);
/*
* Validate parameters in the open packet.
*/
if ( openPacket->OpenType != IcaOpen_Stack &&
openPacket->OpenType != IcaOpen_Channel ) {
ASSERT(FALSE);
return STATUS_INVALID_PARAMETER;
}
/*
* Use the specified ICA connection handle to get a pointer to
* the connection object.
*/
Status = ObReferenceObjectByHandle(
openPacket->IcaHandle,
STANDARD_RIGHTS_READ, // DesiredAccess
*IoFileObjectType,
Irp->RequestorMode,
(PVOID *)&pConnectFileObject,
NULL
);
if ( !NT_SUCCESS(Status) )
return( Status );
/*
* Ensure what we have is a connection object
*/
if (pConnectFileObject->DeviceObject != IcaDeviceObject) {
ASSERT(FALSE);
ObDereferenceObject( pConnectFileObject );
return STATUS_INVALID_PARAMETER;
}
pConnect = pConnectFileObject->FsContext;
ASSERT( pConnect->Header.Type == IcaType_Connection );
if ( pConnect->Header.Type != IcaType_Connection ) {
ObDereferenceObject( pConnectFileObject );
return( STATUS_INVALID_CONNECTION );
}
/*
* Create a new stack or new channel
*/
IcaReferenceConnection( pConnect );
switch ( openPacket->OpenType ) {
case IcaOpen_Stack :
Status = IcaCreateStack( pConnect, openPacket, Irp, IrpSp );
break;
case IcaOpen_Channel :
Status = IcaCreateChannel( pConnect, openPacket, Irp, IrpSp );
break;
}
IcaDereferenceConnection( pConnect );
ObDereferenceObject( pConnectFileObject );
return( Status );
}
NTSTATUS
IcaRead (
IN PIRP Irp,
IN PIO_STACK_LOCATION IrpSp
)
/*++
Routine Description:
This is the read routine for ICA.
Arguments:
Irp - Pointer to I/O request packet
IrpSp - pointer to the stack location to use for this request.
Return Value:
NTSTATUS -- Indicates whether the request was successfully queued.
--*/
{
PICA_HEADER pIcaHeader;
NTSTATUS Status;
/*
* Get pointer to ICA object header.
* If a read routine is not defined, return an error.
*/
pIcaHeader = IrpSp->FileObject->FsContext;
if ( pIcaHeader->pDispatchTable[IRP_MJ_READ] == NULL ) {
Status = STATUS_INVALID_DEVICE_REQUEST;
Irp->IoStatus.Status = Status;
IoCompleteRequest( Irp, IcaPriorityBoost );
return( Status );
}
/*
* Call the read routine for this ICA object.
*/
Status = (pIcaHeader->pDispatchTable[IRP_MJ_READ])(
pIcaHeader, Irp, IrpSp );
return( Status );
}
NTSTATUS
IcaWrite (
IN PIRP Irp,
IN PIO_STACK_LOCATION IrpSp
)
/*++
Routine Description:
This is the write routine for ICA.
Arguments:
Irp - Pointer to I/O request packet
IrpSp - pointer to the stack location to use for this request.
Return Value:
NTSTATUS -- Indicates whether the request was successfully queued.
--*/
{
PICA_HEADER pIcaHeader;
NTSTATUS Status;
/*
* Get pointer to ICA object header.
* If a write routine is not defined, return an error.
*/
pIcaHeader = IrpSp->FileObject->FsContext;
if ( pIcaHeader->pDispatchTable[IRP_MJ_WRITE] == NULL ) {
Status = STATUS_INVALID_DEVICE_REQUEST;
Irp->IoStatus.Status = Status;
IoCompleteRequest( Irp, IcaPriorityBoost );
return( Status );
}
/*
* Call the write routine for this ICA object.
*/
Status = (pIcaHeader->pDispatchTable[IRP_MJ_WRITE])(
pIcaHeader, Irp, IrpSp );
return( Status );
}
NTSTATUS
IcaWriteSync (
IN PIRP Irp,
IN PIO_STACK_LOCATION IrpSp
)
/*++
Routine Description:
This is the flush routine for ICA.
Arguments:
Irp - Pointer to I/O request packet
IrpSp - pointer to the stack location to use for this request.
Return Value:
NTSTATUS -- Indicates whether the request was successfully queued.
--*/
{
PICA_HEADER pIcaHeader;
NTSTATUS Status;
/*
* Get pointer to ICA object header.
* If a flush routine is not defined, return an error.
*/
pIcaHeader = IrpSp->FileObject->FsContext;
if ( pIcaHeader->pDispatchTable[IRP_MJ_FLUSH_BUFFERS] == NULL )
return( STATUS_INVALID_DEVICE_REQUEST );
/*
* Call the flush routine for this ICA object.
*/
Status = (pIcaHeader->pDispatchTable[IRP_MJ_FLUSH_BUFFERS])(
pIcaHeader, Irp, IrpSp );
return( Status );
}
NTSTATUS
IcaDeviceControl (
IN PIRP Irp,
IN PIO_STACK_LOCATION IrpSp
)
/*++
Routine Description:
This is the dispatch routine for ICA IOCTLs.
Arguments:
Irp - Pointer to I/O request packet.
IrpSp - pointer to the stack location to use for this request.
Return Value:
NTSTATUS -- Indicates whether the request was successfully queued.
--*/
{
PICA_HEADER pIcaHeader;
NTSTATUS Status;
/*
* Get pointer to ICA object header.
* If a device control routine is not defined, return an error.
*/
pIcaHeader = IrpSp->FileObject->FsContext;
if ( pIcaHeader->pDispatchTable[IRP_MJ_DEVICE_CONTROL] == NULL )
return( STATUS_INVALID_DEVICE_REQUEST );
/*
* Call the device control routine for this ICA object.
*/
Status = (pIcaHeader->pDispatchTable[IRP_MJ_DEVICE_CONTROL])(
pIcaHeader, Irp, IrpSp );
return( Status );
}
NTSTATUS
IcaCleanup (
IN PIRP Irp,
IN PIO_STACK_LOCATION IrpSp
)
/*++
Routine Description:
This is the routine that handles Cleanup IRPs in ICA.
Arguments:
Irp - Pointer to I/O request packet.
IrpSp - pointer to the IO stack location to use for this request.
Return Value:
NTSTATUS --
--*/
{
PICA_HEADER pIcaHeader;
NTSTATUS Status;
/*
* Get pointer to ICA object header.
* If a cleanup routine is not defined, return an error.
*/
pIcaHeader = IrpSp->FileObject->FsContext;
if ( pIcaHeader->pDispatchTable[IRP_MJ_CLEANUP] == NULL )
return( STATUS_INVALID_DEVICE_REQUEST );
Status = (pIcaHeader->pDispatchTable[IRP_MJ_CLEANUP])(
pIcaHeader, Irp, IrpSp );
return( Status );
}
NTSTATUS
IcaClose (
IN PIRP Irp,
IN PIO_STACK_LOCATION IrpSp
)
/*++
Routine Description:
This is the routine that handles Close IRPs in ICA. It
dereferences the endpoint specified in the IRP, which will result in
the endpoint being freed when all other references go away.
Arguments:
Irp - Pointer to I/O request packet.
IrpSp - pointer to the IO stack location to use for this request.
Return Value:
NTSTATUS -- Indicates whether the request was successfully queued.
--*/
{
PICA_HEADER pIcaHeader;
NTSTATUS Status;
PAGED_CODE( );
/*
* Get pointer to ICA object header.
* If a close routine is not defined, return an error.
*/
pIcaHeader = IrpSp->FileObject->FsContext;
if ( pIcaHeader->pDispatchTable[IRP_MJ_CLOSE] == NULL )
return( STATUS_INVALID_DEVICE_REQUEST );
Status = (pIcaHeader->pDispatchTable[IRP_MJ_CLOSE])(
pIcaHeader, Irp, IrpSp );
return( Status );
}