|
|
/*************************************************************************
* * connect.c * * This module contains routines for managing TerminalServer connections. * * Copyright 1998, Microsoft. * *************************************************************************/
/*
* Includes */ #include <precomp.h>
#pragma hdrstop
NTSTATUS _IcaCallStack( IN PICA_STACK pStack, IN ULONG ProcIndex, IN OUT PVOID pParms );
NTSTATUS IcaDeviceControlConnection ( IN PICA_CONNECTION pConnect, IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp );
NTSTATUS IcaCleanupConnection ( IN PICA_CONNECTION pConnect, IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp );
NTSTATUS IcaCloseConnection ( IN PICA_CONNECTION pConnect, IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp );
NTSTATUS IcaStartStopTrace( IN PICA_TRACE_INFO pTraceInfo, IN PICA_TRACE pTrace );
NTSTATUS IcaUnbindVirtualChannel( IN PICA_CONNECTION pConnect, IN PVIRTUALCHANNELNAME pVirtualName );
/*
* Local procedure prototypes */ PICA_CONNECTION _IcaAllocateConnection( VOID ); VOID _IcaFreeConnection( PICA_CONNECTION );
/*
* Dispatch table for ICA connection objects */ PICA_DISPATCH IcaConnectionDispatchTable[IRP_MJ_MAXIMUM_FUNCTION+1] = { NULL, // IRP_MJ_CREATE
NULL, // IRP_MJ_CREATE_NAMED_PIPE
IcaCloseConnection, // IRP_MJ_CLOSE
NULL, // IRP_MJ_READ
NULL, // IRP_MJ_WRITE
NULL, // IRP_MJ_QUERY_INFORMATION
NULL, // IRP_MJ_SET_INFORMATION
NULL, // IRP_MJ_QUERY_EA
NULL, // IRP_MJ_SET_EA
NULL, // IRP_MJ_FLUSH_BUFFERS
NULL, // IRP_MJ_QUERY_VOLUME_INFORMATION
NULL, // IRP_MJ_SET_VOLUME_INFORMATION
NULL, // IRP_MJ_DIRECTORY_CONTROL
NULL, // IRP_MJ_FILE_SYSTEM_CONTROL
IcaDeviceControlConnection, // IRP_MJ_DEVICE_CONTROL
NULL, // IRP_MJ_INTERNAL_DEVICE_CONTROL
NULL, // IRP_MJ_SHUTDOWN
NULL, // IRP_MJ_LOCK_CONTROL
IcaCleanupConnection, // IRP_MJ_CLEANUP
NULL, // IRP_MJ_CREATE_MAILSLOT
NULL, // IRP_MJ_QUERY_SECURITY
NULL, // IRP_MJ_SET_SECURITY
NULL, // IRP_MJ_SET_POWER
NULL, // IRP_MJ_QUERY_POWER
};
extern PERESOURCE IcaTraceResource;
// resource used to protect access to the code that start/stops the keep alive thread
PERESOURCE g_pKeepAliveResource;
extern NTSTATUS _IcaKeepAlive( IN BOOLEAN startKeepAliveThread, IN ULONG interval );
NTSTATUS IcaCreateConnection ( IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp )
/*++
Routine Description:
This routine is called to create a new ICA_CONNECTION object.
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_CONNECTION pConnect;
/*
* Allocate a new ICA connect object */ pConnect = _IcaAllocateConnection(); if ( pConnect == NULL ) return( STATUS_INSUFFICIENT_RESOURCES );
/*
* Save a pointer to the connection in the file object * so that we can find it in future calls. */ IrpSp->FileObject->FsContext = pConnect;
IcaDereferenceConnection( pConnect );
return( STATUS_SUCCESS ); }
NTSTATUS IcaDeviceControlConnection( IN PICA_CONNECTION pConnect, IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp ) { ICA_TRACE LocalTrace; PICA_TRACE_BUFFER pTraceBuffer; ULONG code; SD_IOCTL SdIoctl; NTSTATUS Status; BOOLEAN bConnectionLocked = FALSE; BYTE *Buffer = NULL; PICA_KEEP_ALIVE pKeepAlive;
/*
* Extract the IOCTL control code and process the request. */ code = IrpSp->Parameters.DeviceIoControl.IoControlCode;
#if DBG
if ( code != IOCTL_ICA_SYSTEM_TRACE && code != IOCTL_ICA_TRACE ) { TRACE(( pConnect, TC_ICADD, TT_API1, "ICADD: IcaDeviceControlConnection, fc %d (enter)\n", (code & 0x3fff) >> 2 )); } #endif
try { switch ( code ) { case IOCTL_ICA_SET_SYSTEM_TRACE :
// This IOCTL should only be invoked if we are called from system process
// If not, we deny the request
if (!((BOOLEAN)IrpSp->FileObject->FsContext2)) { return (STATUS_ACCESS_DENIED); } if ( IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ICA_TRACE) ) return( STATUS_BUFFER_TOO_SMALL ); if ( Irp->RequestorMode != KernelMode ) { ProbeForRead(IrpSp->Parameters.DeviceIoControl.Type3InputBuffer, sizeof(ICA_TRACE), sizeof(BYTE) ); } LocalTrace = *(PICA_TRACE)(IrpSp->Parameters.DeviceIoControl.Type3InputBuffer);
KeEnterCriticalRegion(); ExAcquireResourceExclusiveLite( IcaTraceResource, TRUE );
try {
Status = IcaStartStopTrace( &G_TraceInfo, &LocalTrace );
} finally {
ExReleaseResourceLite( IcaTraceResource ); KeLeaveCriticalRegion(); } break; case IOCTL_ICA_SET_TRACE : // This IOCTL should only be invoked if we are called from system process
// If not, we deny the request
if (!((BOOLEAN)IrpSp->FileObject->FsContext2)) { return (STATUS_ACCESS_DENIED); } if ( IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ICA_TRACE) ) return( STATUS_BUFFER_TOO_SMALL ); if ( Irp->RequestorMode != KernelMode ) { ProbeForRead(IrpSp->Parameters.DeviceIoControl.Type3InputBuffer, IrpSp->Parameters.DeviceIoControl.InputBufferLength, sizeof(BYTE) ); } LocalTrace = *(PICA_TRACE)(IrpSp->Parameters.DeviceIoControl.Type3InputBuffer);
IcaLockConnection( pConnect ); bConnectionLocked = TRUE;
Status = IcaStartStopTrace( &pConnect->TraceInfo, &LocalTrace );
if ( !IsListEmpty(&pConnect->StackHead)) { PICA_STACK pStack; pStack = CONTAINING_RECORD( pConnect->StackHead.Flink, ICA_STACK, StackEntry ); SdIoctl.IoControlCode = code; SdIoctl.InputBuffer = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer; SdIoctl.InputBufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength; SdIoctl.OutputBuffer = NULL; SdIoctl.OutputBufferLength = 0; _IcaCallStack(pStack, SD$IOCTL, &SdIoctl); } IcaUnlockConnection( pConnect ); break; case IOCTL_ICA_SYSTEM_TRACE : if ( IrpSp->Parameters.DeviceIoControl.InputBufferLength < (ULONG)(FIELD_OFFSET(ICA_TRACE_BUFFER,Data[0])) ) return( STATUS_BUFFER_TOO_SMALL ); if ( IrpSp->Parameters.DeviceIoControl.InputBufferLength > sizeof(ICA_TRACE_BUFFER) ) return( STATUS_INVALID_BUFFER_SIZE ); if ( Irp->RequestorMode != KernelMode ) { ProbeForRead(IrpSp->Parameters.DeviceIoControl.Type3InputBuffer, IrpSp->Parameters.DeviceIoControl.InputBufferLength, sizeof(BYTE) ); }
pTraceBuffer = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
KeEnterCriticalRegion(); ExAcquireResourceExclusiveLite( IcaTraceResource, TRUE );
try {
IcaTraceFormat( &G_TraceInfo, pTraceBuffer->TraceClass, pTraceBuffer->TraceEnable, pTraceBuffer->Data );
} finally {
ExReleaseResourceLite( IcaTraceResource ); KeLeaveCriticalRegion(); }
Status = STATUS_SUCCESS; break; case IOCTL_ICA_TRACE : if ( IrpSp->Parameters.DeviceIoControl.InputBufferLength < (ULONG)(FIELD_OFFSET(ICA_TRACE_BUFFER,Data[0])) ) return( STATUS_BUFFER_TOO_SMALL ); if ( IrpSp->Parameters.DeviceIoControl.InputBufferLength > sizeof(ICA_TRACE_BUFFER) ) return( STATUS_INVALID_BUFFER_SIZE ); if ( Irp->RequestorMode != KernelMode ) { ProbeForRead(IrpSp->Parameters.DeviceIoControl.Type3InputBuffer, IrpSp->Parameters.DeviceIoControl.InputBufferLength, sizeof(BYTE) ); }
pTraceBuffer = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer; IcaLockConnection( pConnect ); bConnectionLocked=TRUE; IcaTraceFormat( &pConnect->TraceInfo, pTraceBuffer->TraceClass, pTraceBuffer->TraceEnable, pTraceBuffer->Data ); IcaUnlockConnection( pConnect ); Status = STATUS_SUCCESS; break; case IOCTL_ICA_UNBIND_VIRTUAL_CHANNEL : if ( IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(VIRTUALCHANNELNAME) ) return( STATUS_BUFFER_TOO_SMALL ); if ( Irp->RequestorMode != KernelMode ) { ProbeForRead(IrpSp->Parameters.DeviceIoControl.Type3InputBuffer, sizeof(VIRTUALCHANNELNAME), sizeof(BYTE) ); }
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength) { Buffer = ICA_ALLOCATE_POOL( NonPagedPool, IrpSp->Parameters.DeviceIoControl.InputBufferLength); if (Buffer) { memcpy(Buffer, IrpSp->Parameters.DeviceIoControl.Type3InputBuffer, IrpSp->Parameters.DeviceIoControl.InputBufferLength); } else { Status = STATUS_NO_MEMORY; break; } }
IcaLockConnection( pConnect ); bConnectionLocked = TRUE; Status = IcaUnbindVirtualChannel( pConnect, (PVIRTUALCHANNELNAME)Buffer ); IcaUnlockConnection( pConnect );
break; case IOCTL_ICA_SET_SYSTEM_PARAMETERS: // Settings coming from TermSrv, copy to global variable.
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(TERMSRV_SYSTEM_PARAMS)) return(STATUS_BUFFER_TOO_SMALL); if (Irp->RequestorMode != KernelMode) ProbeForRead(IrpSp->Parameters.DeviceIoControl. Type3InputBuffer, sizeof(TERMSRV_SYSTEM_PARAMS), sizeof(BYTE)); SysParams = *(PTERMSRV_SYSTEM_PARAMS)(IrpSp->Parameters. DeviceIoControl.Type3InputBuffer); Status = STATUS_SUCCESS; break;
case IOCTL_ICA_SYSTEM_KEEP_ALIVE:
// This should only be invoked if we are called from system process
// If not, we deny the request
if (!((BOOLEAN)IrpSp->FileObject->FsContext2)) { return (STATUS_ACCESS_DENIED); } if ( IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ICA_KEEP_ALIVE ) ) return( STATUS_BUFFER_TOO_SMALL );
if ( Irp->RequestorMode != KernelMode ) { ProbeForRead(IrpSp->Parameters.DeviceIoControl.Type3InputBuffer, sizeof(ICA_KEEP_ALIVE ), sizeof(BYTE) ); } pKeepAlive = (PICA_KEEP_ALIVE)(IrpSp->Parameters.DeviceIoControl.Type3InputBuffer);
KeEnterCriticalRegion(); ExAcquireResourceExclusive( g_pKeepAliveResource, TRUE );
try {
Status = _IcaKeepAlive( pKeepAlive->start, pKeepAlive->interval );
} finally {
ExReleaseResource( g_pKeepAliveResource ); KeLeaveCriticalRegion(); }
break;
default: Status = STATUS_INVALID_DEVICE_REQUEST; break; } } except(EXCEPTION_EXECUTE_HANDLER){ Status = GetExceptionCode(); if (bConnectionLocked) { IcaUnlockConnection( pConnect ); } }
if (Buffer) { ICA_FREE_POOL(Buffer); Buffer = NULL; }
#if DBG
if ( code != IOCTL_ICA_SYSTEM_TRACE && code != IOCTL_ICA_TRACE ) { TRACE(( pConnect, TC_ICADD, TT_API1, "ICADD: IcaDeviceControlConnection, fc %d, 0x%x\n", (code & 0x3fff) >> 2, Status )); } #endif
return( Status ); }
NTSTATUS IcaCleanupConnection( IN PICA_CONNECTION pConnect, IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp ) { return( STATUS_SUCCESS ); }
NTSTATUS IcaCloseConnection( IN PICA_CONNECTION pConnect, IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp ) {
/*
* Remove the file object reference for this connection. * This will cause the connection to be deleted when all other * references (including stack/channel references) are gone. */ IcaDereferenceConnection( pConnect );
return( STATUS_SUCCESS ); }
VOID IcaReferenceConnection( IN PICA_CONNECTION pConnect ) {
ASSERT( pConnect->RefCount >= 0 );
/*
* Increment the reference count */ if ( InterlockedIncrement(&pConnect->RefCount) <= 0 ) { ASSERT( FALSE ); } }
VOID IcaDereferenceConnection( IN PICA_CONNECTION pConnect ) {
ASSERT( pConnect->RefCount > 0 );
/*
* Decrement the reference count; if it is 0, free the connection. */ if ( InterlockedDecrement( &pConnect->RefCount) == 0 ) { _IcaFreeConnection( pConnect ); } }
PICA_CONNECTION _IcaAllocateConnection( VOID ) { PICA_CONNECTION pConnect; NTSTATUS Status;
pConnect = ICA_ALLOCATE_POOL( NonPagedPool, sizeof(*pConnect) ); if ( pConnect == NULL ) return NULL;
RtlZeroMemory( pConnect, sizeof(*pConnect) );
/*
* Initialize the reference count to 2, * one for the caller's reference, one for the file object reference. */ pConnect->RefCount = 2;
/*
* Initialize the rest of the connect object */ pConnect->Header.Type = IcaType_Connection; pConnect->Header.pDispatchTable = IcaConnectionDispatchTable; ExInitializeResourceLite( &pConnect->Resource ); ExInitializeResourceLite( &pConnect->ChannelTableLock ); InitializeListHead( &pConnect->StackHead ); InitializeListHead( &pConnect->ChannelHead ); InitializeListHead( &pConnect->VcBindHead );
return( pConnect ); }
VOID _IcaFreeConnection( PICA_CONNECTION pConnect ) { ICA_TRACE TraceControl; PICA_CHANNEL pChannel; PLIST_ENTRY Head;
ASSERT( pConnect->RefCount == 0 ); ASSERT( IsListEmpty( &pConnect->StackHead ) ); ASSERT( IsListEmpty( &pConnect->ChannelHead ) ); ASSERT( IsListEmpty( &pConnect->VcBindHead ) ); ASSERT( !ExIsResourceAcquiredExclusiveLite( &pConnect->Resource ) );
TRACE(( pConnect, TC_ICADD, TT_API2, "ICADD: _IcaFreeConnection: %x\n", pConnect ));
/*
* Close trace file, if any */ RtlZeroMemory( &TraceControl, sizeof(TraceControl) ); (void) IcaStartStopTrace( &pConnect->TraceInfo, &TraceControl );
ExDeleteResourceLite( &pConnect->Resource ); ExDeleteResourceLite( &pConnect->ChannelTableLock );
ICA_FREE_POOL( pConnect ); }
|