2370 lines
64 KiB
C
2370 lines
64 KiB
C
|
/*************************************************************************
|
||
|
* STACK.C
|
||
|
*
|
||
|
* Copyright (C) 1997-1999 Microsoft Corp.
|
||
|
*************************************************************************/
|
||
|
|
||
|
#include "precomp.h"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
/*=============================================================================
|
||
|
== Internal procedures defined
|
||
|
=============================================================================*/
|
||
|
|
||
|
NTSTATUS _IcaStackOpen( HANDLE hIca, HANDLE * phStack, ICA_OPEN_TYPE, PICA_TYPE_INFO );
|
||
|
NTSTATUS _IcaStackIoControlWorker( PSTACK pStack, ULONG, PVOID, ULONG, PVOID, ULONG, PULONG );
|
||
|
NTSTATUS _IcaPushStackAndCreateEndpoint( PSTACK pStack, PWINSTATIONNAME,
|
||
|
PWINSTATIONCONFIG2, PICA_STACK_ADDRESS,
|
||
|
PICA_STACK_ADDRESS );
|
||
|
NTSTATUS _IcaPushStackAndOpenEndpoint( PSTACK pStack, PWINSTATIONNAME,
|
||
|
PWINSTATIONCONFIG2, PVOID, ULONG );
|
||
|
NTSTATUS _IcaPushStack( PSTACK pStack, PWINSTATIONNAME, PWINSTATIONCONFIG2 );
|
||
|
NTSTATUS _IcaPushPd( PSTACK pStack, PWINSTATIONNAME, PWINSTATIONCONFIG2,
|
||
|
PDLLNAME, PPDCONFIG );
|
||
|
NTSTATUS _IcaPushWd( PSTACK pStack, PWINSTATIONNAME, PWINSTATIONCONFIG2 );
|
||
|
VOID _IcaPopStack( PSTACK pStack );
|
||
|
NTSTATUS _IcaPopSd( PSTACK pStack );
|
||
|
NTSTATUS _IcaStackWaitForIca( PSTACK pStack, PWINSTATIONCONFIG2, BOOLEAN * );
|
||
|
void _DecrementStackRef( IN PSTACK pStack );
|
||
|
|
||
|
/*=============================================================================
|
||
|
== Procedures used
|
||
|
=============================================================================*/
|
||
|
|
||
|
NTSTATUS IcaMemoryAllocate( ULONG, PVOID * );
|
||
|
VOID IcaMemoryFree( PVOID );
|
||
|
NTSTATUS _IcaOpen( PHANDLE hIca, PVOID, ULONG );
|
||
|
NTSTATUS _CdOpen( PSTACK pStack, PWINSTATIONCONFIG2 );
|
||
|
VOID _CdClose( PSTACK pStack );
|
||
|
|
||
|
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* IcaStackOpen
|
||
|
*
|
||
|
* Open an ICA stack
|
||
|
*
|
||
|
* ENTRY:
|
||
|
* hIca (input)
|
||
|
* ICA instance handle
|
||
|
* Class (input)
|
||
|
* class (type) of stack
|
||
|
* pStackIoControlCallback (input)
|
||
|
* Pointer to StackIoControl callback procedure
|
||
|
* pCallbackContext (input)
|
||
|
* StackIoControl callback context value
|
||
|
* ppContext (output)
|
||
|
* Pointer to ICA stack context
|
||
|
*
|
||
|
* EXIT:
|
||
|
* STATUS_SUCCESS - Success
|
||
|
* other - Error return code
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
|
||
|
|
||
|
NTSTATUS
|
||
|
IcaStackOpen( IN HANDLE hIca,
|
||
|
IN STACKCLASS Class,
|
||
|
IN PROC pStackIoControlCallback,
|
||
|
IN PVOID pCallbackContext,
|
||
|
OUT HANDLE * ppContext )
|
||
|
{
|
||
|
ICA_TYPE_INFO TypeInfo;
|
||
|
PSTACK pStack;
|
||
|
NTSTATUS Status;
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Allocate Memory for stack context data structure
|
||
|
*/
|
||
|
Status = IcaMemoryAllocate( sizeof(STACK), &pStack );
|
||
|
if ( !NT_SUCCESS(Status) )
|
||
|
goto badalloc;
|
||
|
|
||
|
/*
|
||
|
* Zero STACK data structure
|
||
|
*/
|
||
|
RtlZeroMemory( pStack, sizeof(STACK) );
|
||
|
|
||
|
/*
|
||
|
* Initialize critical section
|
||
|
*/
|
||
|
INITLOCK( &pStack->CritSec, Status );
|
||
|
if ( !NT_SUCCESS( Status ) )
|
||
|
goto badcritsec;
|
||
|
|
||
|
/*
|
||
|
* Open stack handle to ica device driver
|
||
|
*/
|
||
|
RtlZeroMemory( &TypeInfo, sizeof(TypeInfo) );
|
||
|
TypeInfo.StackClass = Class;
|
||
|
Status = _IcaStackOpen( hIca, &pStack->hStack, IcaOpen_Stack, &TypeInfo );
|
||
|
if ( !NT_SUCCESS(Status) )
|
||
|
goto badopen;
|
||
|
|
||
|
/*
|
||
|
* Save StackIoControl and Context callback values
|
||
|
*/
|
||
|
pStack->pCallbackContext = pCallbackContext;
|
||
|
pStack->pStackIoControlCallback = (PSTACKIOCONTROLCALLBACK)pStackIoControlCallback;
|
||
|
|
||
|
*ppContext = pStack;
|
||
|
|
||
|
TRACE(( hIca, TC_ICAAPI, TT_API1, "TSAPI: IcaStackOpen, type %u, success\n", Class ));
|
||
|
|
||
|
return( STATUS_SUCCESS );
|
||
|
|
||
|
/*=============================================================================
|
||
|
== Error returns
|
||
|
=============================================================================*/
|
||
|
|
||
|
badopen:
|
||
|
DELETELOCK( &pStack->CritSec );
|
||
|
|
||
|
badcritsec:
|
||
|
IcaMemoryFree( pStack );
|
||
|
|
||
|
badalloc:
|
||
|
TRACE(( hIca, TC_ICAAPI, TT_ERROR, "TSAPI: IcaStackOpen, type %u, 0x%x\n", Class, Status ));
|
||
|
*ppContext = NULL;
|
||
|
return( Status );
|
||
|
}
|
||
|
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* IcaStackClose
|
||
|
*
|
||
|
* Close an ICA stack
|
||
|
*
|
||
|
* ENTRY:
|
||
|
* pContext (input)
|
||
|
* pointer to ICA stack context
|
||
|
*
|
||
|
* EXIT:
|
||
|
* STATUS_SUCCESS - Success
|
||
|
* other - Error return code
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
|
||
|
NTSTATUS
|
||
|
IcaStackClose( IN HANDLE pContext )
|
||
|
{
|
||
|
NTSTATUS Status;
|
||
|
PSTACK pStack;
|
||
|
|
||
|
pStack = (PSTACK) pContext;
|
||
|
|
||
|
/*
|
||
|
* Lock critical section
|
||
|
*/
|
||
|
LOCK( &pStack->CritSec );
|
||
|
|
||
|
TRACESTACK(( pContext, TC_ICAAPI, TT_API1, "TSAPI: IcaStackClose\n" ));
|
||
|
|
||
|
/*
|
||
|
* Set closing flag
|
||
|
*/
|
||
|
pStack->fClosing = TRUE;
|
||
|
|
||
|
/*
|
||
|
* Unload stack
|
||
|
*/
|
||
|
_IcaPopStack( pContext );
|
||
|
|
||
|
/*
|
||
|
* Wait for reference count to go to zero before we continue
|
||
|
*/
|
||
|
while ( pStack->RefCount > 0 ) {
|
||
|
|
||
|
TRACESTACK(( pStack, TC_ICAAPI, TT_API1, "TSAPI: _IcaPopStack: waiting for refcount %d\n", pStack->RefCount ));
|
||
|
|
||
|
pStack->hCloseEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
|
||
|
ASSERT( pStack->hCloseEvent );
|
||
|
|
||
|
UNLOCK( &pStack->CritSec );
|
||
|
(void) WaitForSingleObject( pStack->hCloseEvent, INFINITE );
|
||
|
LOCK( &pStack->CritSec );
|
||
|
|
||
|
CloseHandle( pStack->hCloseEvent );
|
||
|
pStack->hCloseEvent = NULL;
|
||
|
}
|
||
|
/*
|
||
|
* Close the ICA device driver stack instance
|
||
|
*/
|
||
|
Status = NtClose( pStack->hStack );
|
||
|
pStack->hStack = NULL;
|
||
|
|
||
|
/*
|
||
|
* Unlock critical section
|
||
|
*/
|
||
|
UNLOCK( &pStack->CritSec );
|
||
|
DELETELOCK( &pStack->CritSec );
|
||
|
|
||
|
/*
|
||
|
* Free stack context memory
|
||
|
*/
|
||
|
IcaMemoryFree( pContext );
|
||
|
|
||
|
ASSERT( NT_SUCCESS(Status) );
|
||
|
return( Status );
|
||
|
}
|
||
|
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* IcaStackUnlock
|
||
|
*
|
||
|
* Unlocks an ICA stack
|
||
|
*
|
||
|
* ENTRY:
|
||
|
* pContext (input)
|
||
|
* pointer to ICA stack context
|
||
|
*
|
||
|
* EXIT:
|
||
|
* STATUS_SUCCESS - Success
|
||
|
* other - Error return code
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
|
||
|
NTSTATUS
|
||
|
IcaStackUnlock( IN HANDLE pContext )
|
||
|
{
|
||
|
NTSTATUS Status;
|
||
|
PSTACK pStack;
|
||
|
|
||
|
pStack = (PSTACK) pContext;
|
||
|
|
||
|
/*
|
||
|
* Lock critical section
|
||
|
*/
|
||
|
UNLOCK( &pStack->CritSec );
|
||
|
|
||
|
return( STATUS_SUCCESS );
|
||
|
}
|
||
|
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* IcaStackTerminate
|
||
|
*
|
||
|
* Prepare to close an ICA stack
|
||
|
* (unloads all stack drivers and marks stack as being closed)
|
||
|
*
|
||
|
* ENTRY:
|
||
|
* pContext (input)
|
||
|
* pointer to ICA stack context
|
||
|
*
|
||
|
* EXIT:
|
||
|
* STATUS_SUCCESS - Success
|
||
|
* other - Error return code
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
|
||
|
NTSTATUS
|
||
|
IcaStackTerminate( IN HANDLE pContext )
|
||
|
{
|
||
|
PSTACK pStack;
|
||
|
NTSTATUS Status = STATUS_SUCCESS;
|
||
|
|
||
|
pStack = (PSTACK) pContext;
|
||
|
|
||
|
/*
|
||
|
* Lock critical section
|
||
|
*/
|
||
|
LOCK( &pStack->CritSec );
|
||
|
|
||
|
TRACESTACK(( pContext, TC_ICAAPI, TT_API1, "TSAPI: IcaStackTerminate\n" ));
|
||
|
|
||
|
/*
|
||
|
* Set closing flag
|
||
|
*/
|
||
|
pStack->fClosing = TRUE;
|
||
|
|
||
|
/*
|
||
|
* Unload stack
|
||
|
*/
|
||
|
_IcaPopStack( pContext );
|
||
|
|
||
|
/*
|
||
|
* Unlock critical section
|
||
|
*/
|
||
|
UNLOCK( &pStack->CritSec );
|
||
|
|
||
|
ASSERT( NT_SUCCESS(Status) );
|
||
|
return( Status );
|
||
|
}
|
||
|
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* IcaStackConnectionWait
|
||
|
*
|
||
|
* Load template stack and wait for a connection
|
||
|
*
|
||
|
* NOTE: On an error the endpoint is closed and the stack is unloaded
|
||
|
*
|
||
|
*
|
||
|
* ENTRY:
|
||
|
* pContext (input)
|
||
|
* pointer to ICA stack context
|
||
|
* pWinStationName (input)
|
||
|
* registry name of WinStation
|
||
|
* pWinStationConfig (input)
|
||
|
* pointer to WinStation registry configuration data
|
||
|
* pAddress (input)
|
||
|
* Pointer to optional local address to wait on (or null)
|
||
|
* pEndpoint (output)
|
||
|
* Pointer to buffer to return connection endpoint (optional)
|
||
|
* BufferLength (input)
|
||
|
* length of endpoint data buffer
|
||
|
* pEndpointLength (output)
|
||
|
* pointer to return actual length of endpoint
|
||
|
*
|
||
|
* EXIT:
|
||
|
* STATUS_SUCCESS - Success
|
||
|
* STATUS_BUFFER_TOO_SMALL - endpoint buffer is too small (use *pEndpointLength)
|
||
|
* other - Error return code
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
|
||
|
NTSTATUS
|
||
|
IcaStackConnectionWait( IN HANDLE pContext,
|
||
|
IN PWINSTATIONNAME pWinStationName,
|
||
|
IN PWINSTATIONCONFIG2 pWinStationConfig,
|
||
|
IN PICA_STACK_ADDRESS pAddress,
|
||
|
OUT PVOID pEndpoint,
|
||
|
IN ULONG BufferLength,
|
||
|
OUT PULONG pEndpointLength )
|
||
|
{
|
||
|
NTSTATUS Status;
|
||
|
PSTACK pStack;
|
||
|
BOOLEAN fStackLoaded;
|
||
|
|
||
|
pStack = (PSTACK) pContext;
|
||
|
|
||
|
/*
|
||
|
* Lock critical section
|
||
|
*/
|
||
|
LOCK( &pStack->CritSec );
|
||
|
|
||
|
/*
|
||
|
* load template stack and create stack endpoint
|
||
|
*/
|
||
|
if ( !(fStackLoaded = (BOOLEAN)pStack->fStackLoaded) ) {
|
||
|
Status = _IcaPushStackAndCreateEndpoint( pStack,
|
||
|
pWinStationName,
|
||
|
pWinStationConfig,
|
||
|
pAddress,
|
||
|
NULL );
|
||
|
if ( !NT_SUCCESS(Status) )
|
||
|
goto badcreate;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Now wait for a connection.
|
||
|
*/
|
||
|
Status = _IcaStackIoControl( pStack,
|
||
|
IOCTL_ICA_STACK_CONNECTION_WAIT,
|
||
|
NULL,
|
||
|
0,
|
||
|
pEndpoint,
|
||
|
BufferLength,
|
||
|
pEndpointLength );
|
||
|
if ( !NT_SUCCESS(Status) )
|
||
|
goto badwait;
|
||
|
|
||
|
TRACESTACK(( pContext, TC_ICAAPI, TT_API1, "TSAPI: IcaStackConnectionWait, success\n" ));
|
||
|
|
||
|
/*
|
||
|
* Unlock critical section
|
||
|
*/
|
||
|
UNLOCK( &pStack->CritSec );
|
||
|
|
||
|
return( STATUS_SUCCESS );
|
||
|
|
||
|
/*=============================================================================
|
||
|
== Error returns
|
||
|
=============================================================================*/
|
||
|
/*
|
||
|
* If the stack wasn't already loaded,
|
||
|
* then pop all stack drivers now.
|
||
|
*/
|
||
|
badwait:
|
||
|
if ( !fStackLoaded ) {
|
||
|
_IcaPopStack( pContext );
|
||
|
}
|
||
|
|
||
|
badcreate:
|
||
|
*pEndpointLength = 0;
|
||
|
memset( pEndpoint, 0, BufferLength );
|
||
|
TRACESTACK(( pContext, TC_ICAAPI, TT_ERROR, "TSAPI: IcaStackConnectionWait, 0x%x\n", Status ));
|
||
|
UNLOCK( &pStack->CritSec );
|
||
|
return( Status );
|
||
|
}
|
||
|
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* IcaStackConnectionRequest
|
||
|
*
|
||
|
* Load query stack and try to make a connection with the client
|
||
|
*
|
||
|
* NOTE: On an error the endpoint is NOT closed and the stack is unloaded
|
||
|
*
|
||
|
*
|
||
|
* ENTRY:
|
||
|
* pContext (input)
|
||
|
* pointer to ICA stack context
|
||
|
* pWinStationConfig (input)
|
||
|
* pointer to winstation registry configuration data
|
||
|
* pAddress (input)
|
||
|
* address to connect to (remote address)
|
||
|
* pEndpoint (output)
|
||
|
* Pointer to buffer to return connection endpoint (optional)
|
||
|
* BufferLength (input)
|
||
|
* length of endpoint data buffer
|
||
|
* pEndpointLength (output)
|
||
|
* pointer to return actual length of endpoint
|
||
|
*
|
||
|
*
|
||
|
* EXIT:
|
||
|
* STATUS_SUCCESS - Success
|
||
|
* STATUS_BUFFER_TOO_SMALL - endpoint buffer is too small (use *pEndpointLength)
|
||
|
* other - Error return code
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
|
||
|
NTSTATUS
|
||
|
IcaStackConnectionRequest( IN HANDLE pContext,
|
||
|
IN PWINSTATIONNAME pWinStationName,
|
||
|
IN PWINSTATIONCONFIG2 pWinStationConfig,
|
||
|
IN PICA_STACK_ADDRESS pAddress,
|
||
|
OUT PVOID pEndpoint,
|
||
|
IN ULONG BufferLength,
|
||
|
OUT PULONG pEndpointLength )
|
||
|
{
|
||
|
ULONG ReturnLength;
|
||
|
NTSTATUS Status;
|
||
|
PSTACK pStack;
|
||
|
|
||
|
pStack = (PSTACK) pContext;
|
||
|
|
||
|
/*
|
||
|
* Lock critical section
|
||
|
*/
|
||
|
LOCK( &pStack->CritSec );
|
||
|
|
||
|
/*
|
||
|
* Load template Stack
|
||
|
*/
|
||
|
Status = _IcaPushStack( pContext, pWinStationName, pWinStationConfig );
|
||
|
if ( !NT_SUCCESS(Status) )
|
||
|
goto badpush;
|
||
|
|
||
|
/*
|
||
|
* Now initiate a connection to the specified address
|
||
|
*/
|
||
|
Status = _IcaStackIoControl( pStack,
|
||
|
IOCTL_ICA_STACK_CONNECTION_REQUEST,
|
||
|
pAddress,
|
||
|
sizeof(*pAddress),
|
||
|
pEndpoint,
|
||
|
BufferLength,
|
||
|
pEndpointLength );
|
||
|
if ( !NT_SUCCESS(Status) )
|
||
|
goto badrequest;
|
||
|
|
||
|
TRACESTACK(( pContext, TC_ICAAPI, TT_API1, "TSAPI: IcaStackConnectionRequest, success\n" ));
|
||
|
|
||
|
/*
|
||
|
* Unlock critical section
|
||
|
*/
|
||
|
UNLOCK( &pStack->CritSec );
|
||
|
|
||
|
return( STATUS_SUCCESS );
|
||
|
|
||
|
/*=============================================================================
|
||
|
== Error returns
|
||
|
=============================================================================*/
|
||
|
|
||
|
badrequest:
|
||
|
/* pop all stack drivers */
|
||
|
_IcaPopStack( pContext );
|
||
|
|
||
|
badpush:
|
||
|
*pEndpointLength = 0;
|
||
|
memset( pEndpoint, 0, BufferLength );
|
||
|
TRACESTACK(( pContext, TC_ICAAPI, TT_ERROR, "TSAPI: IcaStackConnectionRequest, 0x%x\n", Status ));
|
||
|
UNLOCK( &pStack->CritSec );
|
||
|
return( Status );
|
||
|
}
|
||
|
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* IcaStackConnectionAccept
|
||
|
*
|
||
|
* Load final stack and complete the connection
|
||
|
*
|
||
|
* ENTRY:
|
||
|
*
|
||
|
* pContext (input)
|
||
|
* pointer to ICA stack context
|
||
|
* - this can be different from the initially connecting stack
|
||
|
* pWinStationName (input)
|
||
|
* registry name of WinStation
|
||
|
* pWinStationConfig (input)
|
||
|
* pointer to winstation registry configuration data
|
||
|
* pEndpoint (input)
|
||
|
* pointer to endpoint data
|
||
|
* EndpointLength (input)
|
||
|
* Length of endpoint
|
||
|
* pStackState (input) (optional)
|
||
|
* Set if this Accept is for a re-connection
|
||
|
* Points to ICA_STACK_STATE_HEADER buffer returned by IcaStackQueryState
|
||
|
* BufferLength (input)
|
||
|
* Length of pStackState buffer
|
||
|
*
|
||
|
* EXIT:
|
||
|
* STATUS_SUCCESS - Success
|
||
|
* other - Error return code
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
|
||
|
NTSTATUS
|
||
|
IcaStackConnectionAccept( IN HANDLE hIca,
|
||
|
IN HANDLE pContext,
|
||
|
IN PWINSTATIONNAME pWinStationName,
|
||
|
IN PWINSTATIONCONFIG2 pWinStationConfig,
|
||
|
IN PVOID pEndpoint,
|
||
|
IN ULONG EndpointLength,
|
||
|
IN PICA_STACK_STATE_HEADER pStackState,
|
||
|
IN ULONG BufferLength,
|
||
|
IN PICA_TRACE pTrace )
|
||
|
{
|
||
|
NTSTATUS Status;
|
||
|
ULONG cbReturned;
|
||
|
ICA_STACK_CONFIG IcaStackConfig;
|
||
|
BOOLEAN fQueryAgain;
|
||
|
BOOLEAN fStackModified;
|
||
|
ULONG i;
|
||
|
PSTACK pStack;
|
||
|
|
||
|
pStack = (PSTACK) pContext;
|
||
|
|
||
|
/*
|
||
|
* Verify parameters
|
||
|
*/
|
||
|
if ( pEndpoint == NULL )
|
||
|
return( STATUS_INVALID_PARAMETER );
|
||
|
|
||
|
/*
|
||
|
* Lock critical section
|
||
|
*/
|
||
|
LOCK( &pStack->CritSec );
|
||
|
|
||
|
/*
|
||
|
* Check if we need to load and open the template stack again
|
||
|
*/
|
||
|
if ( !pStack->fStackLoaded ) {
|
||
|
Status = _IcaPushStackAndOpenEndpoint( pContext,
|
||
|
pWinStationName,
|
||
|
pWinStationConfig,
|
||
|
pEndpoint,
|
||
|
EndpointLength );
|
||
|
if ( !NT_SUCCESS(Status) ) {
|
||
|
goto badaccept;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Enable trace now that the WD is loaded
|
||
|
*/
|
||
|
|
||
|
IcaIoControl( hIca,
|
||
|
IOCTL_ICA_SET_TRACE,
|
||
|
pTrace,
|
||
|
sizeof ( ICA_TRACE ),
|
||
|
NULL,
|
||
|
0,
|
||
|
NULL );
|
||
|
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* If this is a reconnect, then issue set stack state call
|
||
|
* now that we have loaded the required PDs.
|
||
|
*/
|
||
|
if ( pStackState ) {
|
||
|
Status = _IcaStackIoControl( pStack,
|
||
|
IOCTL_ICA_STACK_SET_STATE,
|
||
|
pStackState,
|
||
|
BufferLength,
|
||
|
NULL,
|
||
|
0,
|
||
|
NULL );
|
||
|
if ( !NT_SUCCESS(Status) ) {
|
||
|
goto badaccept;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* If this is not a re-connect of a previous session, then
|
||
|
* prepare the stack for initial negotiation with the client.
|
||
|
*/
|
||
|
} else {
|
||
|
ICA_STACK_CONFIG_DATA ConfigData;
|
||
|
|
||
|
memset(&ConfigData, 0, sizeof(ICA_STACK_CONFIG_DATA));
|
||
|
ConfigData.colorDepth = pWinStationConfig->Config.User.ColorDepth;
|
||
|
ConfigData.fDisableEncryption = pWinStationConfig->Config.User.fDisableEncryption;
|
||
|
ConfigData.encryptionLevel = pWinStationConfig->Config.User.MinEncryptionLevel;
|
||
|
ConfigData.fDisableAutoReconnect = pWinStationConfig->Config.User.fDisableAutoReconnect;
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Send the config data to stack driver
|
||
|
*/
|
||
|
_IcaStackIoControl( pStack,
|
||
|
IOCTL_ICA_STACK_SET_CONFIG,
|
||
|
&ConfigData,
|
||
|
sizeof(ICA_STACK_CONFIG_DATA),
|
||
|
NULL,
|
||
|
0,
|
||
|
NULL);
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Wait for ICA Detect string from client
|
||
|
*/
|
||
|
Status = _IcaStackWaitForIca( pContext,
|
||
|
pWinStationConfig,
|
||
|
&fStackModified );
|
||
|
if ( !NT_SUCCESS(Status) ) {
|
||
|
goto badaccept;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Check if the query stack is different than the template stack
|
||
|
*/
|
||
|
if ( fStackModified ) {
|
||
|
|
||
|
TRACESTACK(( pContext, TC_ICAAPI, TT_API1, "TSAPI: IcaStackConnectionAccept, load query stack\n"));
|
||
|
ASSERT(FALSE);
|
||
|
|
||
|
#ifdef notdef
|
||
|
/*
|
||
|
* Unload all stack drivers except the transport
|
||
|
* and connection drivers
|
||
|
* -- we can not pop the td or cd
|
||
|
* -- we can not issue a cancel i/o
|
||
|
*/
|
||
|
_IcaPopStack( pContext );
|
||
|
|
||
|
/*
|
||
|
* Load and open the new query stack
|
||
|
*/
|
||
|
Status = _IcaPushStackAndOpenEndpoint( pContext,
|
||
|
pWinStationName,
|
||
|
pWinStationConfig,
|
||
|
pEndpoint,
|
||
|
EndpointLength );
|
||
|
if ( !NT_SUCCESS(Status) ) {
|
||
|
goto badaccept;
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* At this point the stack is now set up (again). The client is
|
||
|
* now queried for any configuration changes.
|
||
|
*
|
||
|
* - repeat this loop until WD does not change
|
||
|
*/
|
||
|
do {
|
||
|
|
||
|
/*
|
||
|
* Clear query again flag
|
||
|
*/
|
||
|
fQueryAgain = FALSE;
|
||
|
|
||
|
/*
|
||
|
* Query the client for the optional PD's
|
||
|
*/
|
||
|
Status = _IcaStackIoControl( pStack,
|
||
|
IOCTL_ICA_STACK_CONNECTION_QUERY,
|
||
|
NULL,
|
||
|
0,
|
||
|
&IcaStackConfig,
|
||
|
sizeof(IcaStackConfig),
|
||
|
&cbReturned );
|
||
|
|
||
|
if ( !NT_SUCCESS(Status) ) {
|
||
|
TRACESTACK(( pContext, TC_ICAAPI, TT_ERROR, "TSAPI: IcaStackConnectionAccept: IOCTL_ICA_STACK_CONNECTION_QUERY, 0x%x\n", Status ));
|
||
|
goto badaccept;
|
||
|
}
|
||
|
|
||
|
if ( cbReturned != sizeof(IcaStackConfig) ) {
|
||
|
TRACESTACK(( pContext, TC_ICAAPI, TT_ERROR, "TSAPI: IcaStackConnectionAccept: Bad size %d from IOCTL_ICA_STACK_CONNECTION_QUERY\n", cbReturned ));
|
||
|
Status = STATUS_INVALID_BUFFER_SIZE;
|
||
|
goto badaccept;
|
||
|
}
|
||
|
|
||
|
TRACESTACK(( pContext, TC_ICAAPI, TT_API1, "TSAPI: IcaStackConnectionAccept: IOCTL_ICA_STACK_CONNECTION_QUERY success\n" ));
|
||
|
|
||
|
/*
|
||
|
* If the WD changed we must load it (and the rest of the stack) and
|
||
|
* reissue the query.
|
||
|
*/
|
||
|
if ( _wcsnicmp( IcaStackConfig.WdDLL,
|
||
|
pWinStationConfig->Wd.WdDLL,
|
||
|
DLLNAME_LENGTH ) ) {
|
||
|
|
||
|
TRACESTACK(( pContext, TC_ICAAPI, TT_API1, "TSAPI: IcaStackConnectionAccept WD changing from %S to %S\n", pWinStationConfig->Wd.WdDLL, IcaStackConfig.WdDLL ));
|
||
|
|
||
|
memcpy( pWinStationConfig->Wd.WdDLL,
|
||
|
IcaStackConfig.WdDLL,
|
||
|
sizeof( pWinStationConfig->Wd.WdDLL ) );
|
||
|
|
||
|
fQueryAgain = TRUE;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* If no new modules were requested, we are done querying
|
||
|
*/
|
||
|
if ( !fQueryAgain && (IcaStackConfig.SdClass[0] == SdNone) )
|
||
|
break;
|
||
|
|
||
|
/*
|
||
|
* Pop the WD to load new PD's underneath.
|
||
|
*/
|
||
|
Status = _IcaPopSd( pContext );
|
||
|
if ( !NT_SUCCESS(Status) ) {
|
||
|
goto badaccept;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Push Optional PD's
|
||
|
*/
|
||
|
for ( i=0; i < SdClass_Maximum; i++ ) {
|
||
|
|
||
|
if ( IcaStackConfig.SdClass[i] == SdNone )
|
||
|
break;
|
||
|
|
||
|
Status = _IcaPushPd( pContext,
|
||
|
pWinStationName,
|
||
|
pWinStationConfig,
|
||
|
IcaStackConfig.SdDLL[i],
|
||
|
&pWinStationConfig->Pd[0] );
|
||
|
|
||
|
/*
|
||
|
* If the PD driver is not found, the client is using an optional
|
||
|
* PD that is not supported by the host. Continue loading and let
|
||
|
* the client and server negoatiate the connection.
|
||
|
*/
|
||
|
if ( !NT_SUCCESS(Status) && (Status != STATUS_OBJECT_NAME_NOT_FOUND) ) {
|
||
|
goto badaccept;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Re-push the WD
|
||
|
*/
|
||
|
Status = _IcaPushWd( pContext, pWinStationName, pWinStationConfig );
|
||
|
if ( !NT_SUCCESS(Status) ) {
|
||
|
goto badaccept;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Re-Enable trace now that the WD is loaded
|
||
|
*/
|
||
|
IcaIoControl( hIca,
|
||
|
IOCTL_ICA_SET_TRACE,
|
||
|
pTrace,
|
||
|
sizeof ( ICA_TRACE ),
|
||
|
NULL,
|
||
|
0,
|
||
|
NULL );
|
||
|
|
||
|
} while ( fQueryAgain );
|
||
|
|
||
|
/*
|
||
|
* If this is a reconnect, then issue set stack state call
|
||
|
* now that we have loaded the optional PDs.
|
||
|
*/
|
||
|
if ( pStackState ) {
|
||
|
Status = _IcaStackIoControl( pStack,
|
||
|
IOCTL_ICA_STACK_SET_STATE,
|
||
|
pStackState,
|
||
|
BufferLength,
|
||
|
NULL,
|
||
|
0,
|
||
|
NULL );
|
||
|
if ( !NT_SUCCESS(Status) ) {
|
||
|
goto badaccept;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Send host module data to client
|
||
|
*/
|
||
|
Status = _IcaStackIoControl( pStack,
|
||
|
IOCTL_ICA_STACK_CONNECTION_SEND,
|
||
|
NULL,
|
||
|
0,
|
||
|
NULL,
|
||
|
0,
|
||
|
NULL );
|
||
|
if ( !NT_SUCCESS(Status) )
|
||
|
goto badaccept;
|
||
|
|
||
|
TRACESTACK(( pContext, TC_ICAAPI, TT_API1, "TSAPI: IcaStackConnectionAccept, success\n" ));
|
||
|
|
||
|
/*
|
||
|
* Leave the critical section locked because the protocol sequence has
|
||
|
* not been finished. The sequence will be finished by the licensing core
|
||
|
* in termsrv.exe, and the critical section will be unlocked at that point.
|
||
|
*/
|
||
|
//UNLOCK( &pStack->CritSec );
|
||
|
|
||
|
return( STATUS_SUCCESS );
|
||
|
|
||
|
/*=============================================================================
|
||
|
== Error returns
|
||
|
=============================================================================*/
|
||
|
|
||
|
badaccept:
|
||
|
/* pop all stack drivers */
|
||
|
_IcaPopStack( pContext );
|
||
|
|
||
|
TRACESTACK(( pContext, TC_ICAAPI, TT_ERROR, "TSAPI: IcaStackConnectionAccept, 0x%x\n", Status ));
|
||
|
UNLOCK( &pStack->CritSec );
|
||
|
return( Status );
|
||
|
}
|
||
|
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* IcaStackQueryState
|
||
|
*
|
||
|
* Query stack driver state information
|
||
|
*
|
||
|
* ENTRY:
|
||
|
* pContext (input)
|
||
|
* pointer to ICA stack context
|
||
|
* - this can be different from the initially connecting stack
|
||
|
*
|
||
|
* pStackState (output)
|
||
|
* pointer to buffer to return stack state information
|
||
|
*
|
||
|
* BufferLength (input)
|
||
|
* Length of pStackState buffer
|
||
|
*
|
||
|
* pStateLength (output)
|
||
|
* length of returned stack state information
|
||
|
*
|
||
|
* EXIT:
|
||
|
* STATUS_SUCCESS - Success
|
||
|
* other - Error return code
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
|
||
|
NTSTATUS
|
||
|
IcaStackQueryState( IN HANDLE pContext,
|
||
|
OUT PICA_STACK_STATE_HEADER pStackState,
|
||
|
IN ULONG BufferLength,
|
||
|
OUT PULONG pStateLength )
|
||
|
{
|
||
|
NTSTATUS Status;
|
||
|
PSTACK pStack;
|
||
|
|
||
|
pStack = (PSTACK) pContext;
|
||
|
|
||
|
/*
|
||
|
* Lock critical section
|
||
|
*/
|
||
|
LOCK( &pStack->CritSec );
|
||
|
|
||
|
/*
|
||
|
* Query state
|
||
|
*/
|
||
|
Status = _IcaStackIoControl( pContext,
|
||
|
IOCTL_ICA_STACK_QUERY_STATE,
|
||
|
NULL,
|
||
|
0,
|
||
|
pStackState,
|
||
|
BufferLength,
|
||
|
pStateLength );
|
||
|
|
||
|
TRACESTACK(( pContext, TC_ICAAPI, TT_API1, "TSAPI: IcaStackQueryState, 0x%x\n", Status ));
|
||
|
|
||
|
/*
|
||
|
* Unlock critical section
|
||
|
*/
|
||
|
UNLOCK( &pStack->CritSec );
|
||
|
|
||
|
return( Status );
|
||
|
}
|
||
|
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* IcaStackCreateShadowEndpoint
|
||
|
*
|
||
|
* Load template stack and create the endpoint
|
||
|
*
|
||
|
*
|
||
|
* ENTRY:
|
||
|
* pContext (input)
|
||
|
* pointer to ICA stack context
|
||
|
* pWinStationConfig (input)
|
||
|
* pointer to winstation registry configuration data
|
||
|
* pAddressIn (input)
|
||
|
* Pointer to local address of endpoint to create
|
||
|
* pAddressOut (output)
|
||
|
* Pointer to location to return address of endpoint created
|
||
|
*
|
||
|
* EXIT:
|
||
|
* STATUS_SUCCESS - Success
|
||
|
* STATUS_BUFFER_TOO_SMALL - endpoint buffer is too small (use *pEndpointLength)
|
||
|
* other - Error return code
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
|
||
|
NTSTATUS
|
||
|
IcaStackCreateShadowEndpoint( HANDLE pContext,
|
||
|
PWINSTATIONNAME pWinStationName,
|
||
|
PWINSTATIONCONFIG2 pWinStationConfig,
|
||
|
PICA_STACK_ADDRESS pAddressIn,
|
||
|
PICA_STACK_ADDRESS pAddressOut )
|
||
|
{
|
||
|
NTSTATUS Status;
|
||
|
PSTACK pStack;
|
||
|
|
||
|
pStack = (PSTACK) pContext;
|
||
|
|
||
|
/*
|
||
|
* Lock critical section
|
||
|
*/
|
||
|
LOCK( &pStack->CritSec );
|
||
|
|
||
|
/*
|
||
|
* load template stack and create stack endpoint
|
||
|
*/
|
||
|
if ( pStack->fStackLoaded ) {
|
||
|
Status = STATUS_ADDRESS_ALREADY_ASSOCIATED;
|
||
|
} else {
|
||
|
Status = _IcaPushStackAndCreateEndpoint( pStack,
|
||
|
pWinStationName,
|
||
|
pWinStationConfig,
|
||
|
pAddressIn,
|
||
|
pAddressOut );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Unlock critical section
|
||
|
*/
|
||
|
UNLOCK( &pStack->CritSec );
|
||
|
|
||
|
if ( !NT_SUCCESS( Status ) ) {
|
||
|
TRACESTACK(( pStack, TC_ICAAPI, TT_API1, "TSAPI: IcaStackCreateShadowEndpoint, success\n" ));
|
||
|
} else {
|
||
|
TRACESTACK(( pStack, TC_ICAAPI, TT_ERROR, "TSAPI: IcaStackCreateShadowEndpoint, 0x%x\n", Status ));
|
||
|
}
|
||
|
|
||
|
return( Status );
|
||
|
}
|
||
|
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* IcaStackConnectionClose
|
||
|
*
|
||
|
* Close the connection endpoint
|
||
|
*
|
||
|
* This is the only way to close the connecting connection.
|
||
|
*
|
||
|
* ENTRY:
|
||
|
* pContext (input)
|
||
|
* pointer to ICA stack context
|
||
|
* pWinStationConfig (input)
|
||
|
* pointer to winstation registry configuration data
|
||
|
* pEndpoint (input)
|
||
|
* Structure defining connection endpoint
|
||
|
* EndpointLength (input)
|
||
|
* Length of endpoint
|
||
|
*
|
||
|
* EXIT:
|
||
|
* STATUS_SUCCESS - Success
|
||
|
* other - Error return code
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
|
||
|
NTSTATUS
|
||
|
IcaStackConnectionClose( IN HANDLE pContext,
|
||
|
IN PWINSTATIONCONFIG2 pWinStationConfig,
|
||
|
IN PVOID pEndpoint,
|
||
|
IN ULONG EndpointLength
|
||
|
)
|
||
|
{
|
||
|
ULONG cbReturned;
|
||
|
NTSTATUS Status;
|
||
|
PSTACK pStack;
|
||
|
BOOLEAN fPopStack = FALSE;
|
||
|
|
||
|
pStack = (PSTACK) pContext;
|
||
|
|
||
|
/*
|
||
|
* Lock critical section
|
||
|
*/
|
||
|
LOCK( &pStack->CritSec );
|
||
|
|
||
|
/*
|
||
|
* If necessary, load the template stack
|
||
|
* - we can't issue ioctls without a stack
|
||
|
*/
|
||
|
if ( !pStack->fStackLoaded ) {
|
||
|
|
||
|
/*
|
||
|
* Load and open the template stack
|
||
|
*/
|
||
|
Status = _IcaPushStackAndOpenEndpoint( pContext,
|
||
|
TEXT(""),
|
||
|
pWinStationConfig,
|
||
|
pEndpoint,
|
||
|
EndpointLength );
|
||
|
if ( !NT_SUCCESS(Status) ) {
|
||
|
goto badclose;
|
||
|
}
|
||
|
|
||
|
fPopStack = TRUE; // remember we have to pop the stack below
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Close endpoint
|
||
|
*/
|
||
|
Status = _IcaStackIoControl( pStack,
|
||
|
IOCTL_ICA_STACK_CLOSE_ENDPOINT,
|
||
|
NULL,
|
||
|
0,
|
||
|
NULL,
|
||
|
0,
|
||
|
NULL );
|
||
|
|
||
|
/*
|
||
|
* Pop stack drivers if we loaded them above
|
||
|
*/
|
||
|
if ( fPopStack )
|
||
|
_IcaPopStack( pContext );
|
||
|
|
||
|
badclose:
|
||
|
TRACESTACK(( pContext, TC_ICAAPI, TT_API1, "TSAPI: IcaStackConnectionClose, 0x%x\n", Status ));
|
||
|
UNLOCK( &pStack->CritSec );
|
||
|
return( Status );
|
||
|
}
|
||
|
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* IcaStackCallback
|
||
|
*
|
||
|
* dial specified phone number and make connection to client
|
||
|
*
|
||
|
* NOTE: On an error the endpoint is NOT closed and the stack is unloaded
|
||
|
*
|
||
|
*
|
||
|
* ENTRY:
|
||
|
*
|
||
|
* pContext (input)
|
||
|
* pointer to ICA stack context
|
||
|
* pWinStationConfig (input)
|
||
|
* pointer to winstation registry configuration data
|
||
|
* pPhoneNumber (input)
|
||
|
* pointer to client phone number
|
||
|
* pEndpoint (output)
|
||
|
* Pointer to buffer to return connection endpoint
|
||
|
* BufferLength (input)
|
||
|
* length of endpoint data buffer
|
||
|
* pEndpointLength (output)
|
||
|
* pointer to return actual length of endpoint
|
||
|
*
|
||
|
*
|
||
|
* EXIT:
|
||
|
* STATUS_SUCCESS - Success
|
||
|
* STATUS_BUFFER_TOO_SMALL - endpoint buffer is too small (use *pEndpointLength)
|
||
|
* other - Error return code
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
|
||
|
NTSTATUS
|
||
|
IcaStackCallback( IN HANDLE pContext,
|
||
|
IN PWINSTATIONCONFIG2 pWinStationConfig,
|
||
|
IN WCHAR * pPhoneNumber,
|
||
|
OUT PVOID pEndpoint,
|
||
|
IN ULONG BufferLength,
|
||
|
OUT PULONG pEndpointLength )
|
||
|
{
|
||
|
NTSTATUS Status;
|
||
|
ICA_STACK_CALLBACK Cb;
|
||
|
PSTACK pStack;
|
||
|
|
||
|
pStack = (PSTACK) pContext;
|
||
|
|
||
|
/*
|
||
|
* Lock critical section
|
||
|
*/
|
||
|
LOCK( &pStack->CritSec );
|
||
|
|
||
|
wcscpy( Cb.PhoneNumber, pPhoneNumber );
|
||
|
|
||
|
Status = _IcaStackIoControl( pContext,
|
||
|
IOCTL_ICA_STACK_CALLBACK_INITIATE,
|
||
|
&Cb,
|
||
|
sizeof(Cb),
|
||
|
pEndpoint,
|
||
|
BufferLength,
|
||
|
pEndpointLength );
|
||
|
|
||
|
|
||
|
TRACESTACK(( pContext, TC_ICAAPI, TT_API1,
|
||
|
"TSAPI: IcaStackCallback: %S, 0x%x\n",
|
||
|
pPhoneNumber, Status ));
|
||
|
UNLOCK( &pStack->CritSec );
|
||
|
return( Status );
|
||
|
}
|
||
|
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* IcaStackDisconnect
|
||
|
*
|
||
|
* Disconnect the specified stack from its ICA connection
|
||
|
*
|
||
|
*
|
||
|
* ENTRY:
|
||
|
*
|
||
|
* pContext (input)
|
||
|
* pointer to ICA stack context
|
||
|
* hIca (input)
|
||
|
* handle to temp ICA connection
|
||
|
* pCallbackContext (input)
|
||
|
* New StackIoControl callback context value
|
||
|
*
|
||
|
*
|
||
|
* EXIT:
|
||
|
* STATUS_SUCCESS - Success
|
||
|
* other - Error return code
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
|
||
|
NTSTATUS
|
||
|
IcaStackDisconnect(
|
||
|
HANDLE pContext,
|
||
|
HANDLE hIca,
|
||
|
PVOID pCallbackContext
|
||
|
)
|
||
|
{
|
||
|
PSTACK pStack;
|
||
|
ICA_STACK_RECONNECT IoctlReconnect;
|
||
|
NTSTATUS Status;
|
||
|
|
||
|
pStack = (PSTACK) pContext;
|
||
|
|
||
|
/*
|
||
|
* Lock critical section
|
||
|
*/
|
||
|
LOCK( &pStack->CritSec );
|
||
|
|
||
|
IoctlReconnect.hIca = hIca;
|
||
|
Status = _IcaStackIoControl( pContext,
|
||
|
IOCTL_ICA_STACK_DISCONNECT,
|
||
|
&IoctlReconnect,
|
||
|
sizeof(IoctlReconnect),
|
||
|
NULL,
|
||
|
0,
|
||
|
NULL );
|
||
|
if ( NT_SUCCESS( Status ) ) {
|
||
|
pStack->pCallbackContext = pCallbackContext;
|
||
|
}
|
||
|
|
||
|
UNLOCK( &pStack->CritSec );
|
||
|
return( Status );
|
||
|
}
|
||
|
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* IcaStackReconnect
|
||
|
*
|
||
|
* Reconnect the specified stack to a new ICA connection
|
||
|
*
|
||
|
*
|
||
|
* ENTRY:
|
||
|
*
|
||
|
* pContext (input)
|
||
|
* pointer to ICA stack context
|
||
|
* hIca (input)
|
||
|
* handle to temp ICA connection
|
||
|
* pCallbackContext (input)
|
||
|
* New StackIoControl callback context value
|
||
|
* sessionId (input)
|
||
|
* Session ID of the Winstation we are reconnecting to
|
||
|
*
|
||
|
*
|
||
|
* EXIT:
|
||
|
* STATUS_SUCCESS - Success
|
||
|
* other - Error return code
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
|
||
|
NTSTATUS
|
||
|
IcaStackReconnect(
|
||
|
HANDLE pContext,
|
||
|
HANDLE hIca,
|
||
|
PVOID pCallbackContext,
|
||
|
ULONG sessionId
|
||
|
)
|
||
|
{
|
||
|
PSTACK pStack;
|
||
|
ICA_STACK_RECONNECT IoctlReconnect;
|
||
|
PVOID SaveContext;
|
||
|
NTSTATUS Status;
|
||
|
|
||
|
pStack = (PSTACK) pContext;
|
||
|
|
||
|
/*
|
||
|
* Lock critical section
|
||
|
*/
|
||
|
LOCK( &pStack->CritSec );
|
||
|
|
||
|
SaveContext = pStack->pCallbackContext;
|
||
|
pStack->pCallbackContext = pCallbackContext;
|
||
|
|
||
|
IoctlReconnect.hIca = hIca;
|
||
|
IoctlReconnect.sessionId = sessionId;
|
||
|
Status = _IcaStackIoControl( pContext,
|
||
|
IOCTL_ICA_STACK_RECONNECT,
|
||
|
&IoctlReconnect,
|
||
|
sizeof(IoctlReconnect),
|
||
|
NULL,
|
||
|
0,
|
||
|
NULL );
|
||
|
if ( !NT_SUCCESS( Status ) ) {
|
||
|
pStack->pCallbackContext = SaveContext;
|
||
|
}
|
||
|
|
||
|
UNLOCK( &pStack->CritSec );
|
||
|
return( Status );
|
||
|
}
|
||
|
|
||
|
|
||
|
/*******************************************************************************
|
||
|
*
|
||
|
* IcaStackTrace
|
||
|
*
|
||
|
* Write a trace record to the winstation trace file
|
||
|
*
|
||
|
* ENTRY:
|
||
|
* pContext (input)
|
||
|
* pointer to ICA stack context
|
||
|
* TraceClass (input)
|
||
|
* trace class bit mask
|
||
|
* TraceEnable (input)
|
||
|
* trace type bit mask
|
||
|
* Format (input)
|
||
|
* format string
|
||
|
* ... (input)
|
||
|
* enough arguments to satisfy format string
|
||
|
*
|
||
|
* EXIT:
|
||
|
* nothing
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
VOID cdecl
|
||
|
IcaStackTrace( IN HANDLE pContext,
|
||
|
IN ULONG TraceClass,
|
||
|
IN ULONG TraceEnable,
|
||
|
IN char * Format,
|
||
|
IN ... )
|
||
|
{
|
||
|
ICA_TRACE_BUFFER Buffer;
|
||
|
va_list arg_marker;
|
||
|
ULONG Length;
|
||
|
PSTACK pStack;
|
||
|
|
||
|
pStack = (PSTACK) pContext;
|
||
|
|
||
|
va_start( arg_marker, Format );
|
||
|
|
||
|
Length = (ULONG) _vsnprintf( Buffer.Data, sizeof(Buffer.Data), Format, arg_marker ) + 1;
|
||
|
|
||
|
Buffer.TraceClass = TraceClass;
|
||
|
Buffer.TraceEnable = TraceEnable;
|
||
|
Buffer.DataLength = Length;
|
||
|
if (pStack->hStack != NULL) {
|
||
|
(void) IcaIoControl( pStack->hStack,
|
||
|
IOCTL_ICA_STACK_TRACE,
|
||
|
&Buffer,
|
||
|
sizeof(Buffer) - sizeof(Buffer.Data) + Length,
|
||
|
NULL,
|
||
|
0,
|
||
|
NULL );
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* IcaStackIoControl
|
||
|
*
|
||
|
* Generic interface to an ICA stack (with locking)
|
||
|
*
|
||
|
* ENTRY:
|
||
|
* pContext (input)
|
||
|
* pointer to ICA stack context
|
||
|
* IoControlCode (input)
|
||
|
* I/O control code
|
||
|
* pInBuffer (input)
|
||
|
* Pointer to input parameters
|
||
|
* InBufferSize (input)
|
||
|
* Size of pInBuffer
|
||
|
* pOutBuffer (output)
|
||
|
* Pointer to output buffer
|
||
|
* OutBufferSize (input)
|
||
|
* Size of pOutBuffer
|
||
|
* pBytesReturned (output)
|
||
|
* Pointer to number of bytes returned
|
||
|
*
|
||
|
* EXIT:
|
||
|
* STATUS_SUCCESS - Success
|
||
|
* other - Error return code
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
|
||
|
NTSTATUS
|
||
|
IcaStackIoControl( IN HANDLE pContext,
|
||
|
IN ULONG IoControlCode,
|
||
|
IN PVOID pInBuffer,
|
||
|
IN ULONG InBufferSize,
|
||
|
OUT PVOID pOutBuffer,
|
||
|
IN ULONG OutBufferSize,
|
||
|
OUT PULONG pBytesReturned )
|
||
|
{
|
||
|
NTSTATUS Status;
|
||
|
PSTACK pStack;
|
||
|
|
||
|
pStack = (PSTACK) pContext;
|
||
|
|
||
|
/*
|
||
|
* Lock critical section
|
||
|
*/
|
||
|
LOCK( &pStack->CritSec );
|
||
|
|
||
|
/*
|
||
|
* Call worker routine
|
||
|
*/
|
||
|
Status = _IcaStackIoControlWorker( pContext,
|
||
|
IoControlCode,
|
||
|
pInBuffer,
|
||
|
InBufferSize,
|
||
|
pOutBuffer,
|
||
|
OutBufferSize,
|
||
|
pBytesReturned );
|
||
|
|
||
|
/*
|
||
|
* Unlock critical section
|
||
|
*/
|
||
|
UNLOCK( &pStack->CritSec );
|
||
|
|
||
|
return( Status );
|
||
|
}
|
||
|
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* IcaPushConsoleStack
|
||
|
*
|
||
|
* Load initial stack
|
||
|
*
|
||
|
* stack push for each stack driver
|
||
|
* in order td - pd - wd
|
||
|
*
|
||
|
* ENTRY:
|
||
|
* pStack (input)
|
||
|
* pointer to ICA stack structure
|
||
|
* pWinStationName (input)
|
||
|
* registry name of WinStation
|
||
|
* pWinStationConfig (input)
|
||
|
* pointer to winstation registry configuration data
|
||
|
*
|
||
|
* EXIT:
|
||
|
* STATUS_SUCCESS - Success
|
||
|
* other - Error return code
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
|
||
|
NTSTATUS
|
||
|
IcaPushConsoleStack( IN HANDLE pContext,
|
||
|
IN PWINSTATIONNAME pWinStationName,
|
||
|
IN PWINSTATIONCONFIG2 pWinStationConfig,
|
||
|
IN PVOID pModuleData,
|
||
|
IN ULONG ModuleDataLength )
|
||
|
{
|
||
|
NTSTATUS Status;
|
||
|
PSTACK pStack;
|
||
|
ULONG cbReturned;
|
||
|
ULONG i;
|
||
|
|
||
|
pStack = (PSTACK) pContext;
|
||
|
|
||
|
LOCK( &pStack->CritSec );
|
||
|
|
||
|
/*
|
||
|
* build the stack
|
||
|
*/
|
||
|
Status = _IcaPushStack( pStack,
|
||
|
pWinStationName,
|
||
|
pWinStationConfig);
|
||
|
|
||
|
|
||
|
if ( !NT_SUCCESS(Status) ) {
|
||
|
KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "IcaPushConsoleStack _IcaPushStack failed\n"));
|
||
|
goto failure;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* and now set up the connection to the console
|
||
|
*/
|
||
|
Status = _IcaStackIoControl( pStack,
|
||
|
IOCTL_ICA_STACK_CONSOLE_CONNECT,
|
||
|
pModuleData,
|
||
|
ModuleDataLength,
|
||
|
NULL,
|
||
|
0,
|
||
|
&cbReturned );
|
||
|
|
||
|
if ( !NT_SUCCESS(Status) )
|
||
|
{
|
||
|
KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "IcaPushConsoleStack - stack wait failed\n"));
|
||
|
goto failure;
|
||
|
}
|
||
|
|
||
|
KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_INFO_LEVEL, "IcaPushConsoleStack - done stack wait\n"));
|
||
|
|
||
|
failure:
|
||
|
UNLOCK( &pStack->CritSec );
|
||
|
|
||
|
return( Status );
|
||
|
}
|
||
|
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* _IcaStackOpen
|
||
|
*
|
||
|
* Open an ICA stack or an ICA channel
|
||
|
*
|
||
|
* ENTRY:
|
||
|
* hIca (input)
|
||
|
* ICA instance handle
|
||
|
*
|
||
|
* phStack (output)
|
||
|
* Pointer to ICA stack or channel handle
|
||
|
*
|
||
|
* OpenType (input)
|
||
|
* ICA open type
|
||
|
*
|
||
|
* pTypeInfo (input)
|
||
|
* Pointer to ICA type info
|
||
|
*
|
||
|
* EXIT:
|
||
|
* STATUS_SUCCESS - Success
|
||
|
* other - Error return code
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
|
||
|
NTSTATUS
|
||
|
_IcaStackOpen( HANDLE hIca,
|
||
|
HANDLE * phStack,
|
||
|
ICA_OPEN_TYPE OpenType,
|
||
|
PICA_TYPE_INFO pTypeInfo )
|
||
|
{
|
||
|
NTSTATUS Status;
|
||
|
PFILE_FULL_EA_INFORMATION pEa = NULL;
|
||
|
ICA_OPEN_PACKET UNALIGNED * pIcaOpenPacket;
|
||
|
ULONG cbEa = sizeof( FILE_FULL_EA_INFORMATION )
|
||
|
+ ICA_OPEN_PACKET_NAME_LENGTH
|
||
|
+ sizeof( ICA_OPEN_PACKET );
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Allocate some memory for the EA buffer
|
||
|
*/
|
||
|
Status = IcaMemoryAllocate( cbEa, &pEa );
|
||
|
if ( !NT_SUCCESS(Status) )
|
||
|
goto done;
|
||
|
|
||
|
/*
|
||
|
* Initialize the EA buffer
|
||
|
*/
|
||
|
pEa->NextEntryOffset = 0;
|
||
|
pEa->Flags = 0;
|
||
|
pEa->EaNameLength = ICA_OPEN_PACKET_NAME_LENGTH;
|
||
|
memcpy( pEa->EaName, ICAOPENPACKET, ICA_OPEN_PACKET_NAME_LENGTH + 1 );
|
||
|
|
||
|
pEa->EaValueLength = sizeof( ICA_OPEN_PACKET );
|
||
|
pIcaOpenPacket = (ICA_OPEN_PACKET UNALIGNED *)(pEa->EaName +
|
||
|
pEa->EaNameLength + 1);
|
||
|
|
||
|
/*
|
||
|
* Now put the open packe parameters into the EA buffer
|
||
|
*/
|
||
|
pIcaOpenPacket->IcaHandle = hIca;
|
||
|
pIcaOpenPacket->OpenType = OpenType;
|
||
|
pIcaOpenPacket->TypeInfo = *pTypeInfo;
|
||
|
|
||
|
|
||
|
Status = _IcaOpen( phStack, pEa, cbEa );
|
||
|
|
||
|
done:
|
||
|
if ( pEa ) {
|
||
|
IcaMemoryFree( pEa );
|
||
|
}
|
||
|
|
||
|
return( Status );
|
||
|
}
|
||
|
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* _IcaStackIoControl
|
||
|
*
|
||
|
* Local (ICAAPI) interface to an ICA stack through callback routine
|
||
|
*
|
||
|
* ENTRY:
|
||
|
* pStack (input)
|
||
|
* pointer to ICA stack structure
|
||
|
* IoControlCode (input)
|
||
|
* I/O control code
|
||
|
* pInBuffer (input)
|
||
|
* Pointer to input parameters
|
||
|
* InBufferSize (input)
|
||
|
* Size of pInBuffer
|
||
|
* pOutBuffer (output)
|
||
|
* Pointer to output buffer
|
||
|
* OutBufferSize (input)
|
||
|
* Size of pOutBuffer
|
||
|
* pBytesReturned (output)
|
||
|
* Pointer to number of bytes returned
|
||
|
*
|
||
|
* EXIT:
|
||
|
* STATUS_SUCCESS - Success
|
||
|
* other - Error return code
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
|
||
|
NTSTATUS
|
||
|
_IcaStackIoControl( IN HANDLE pContext,
|
||
|
IN ULONG IoControlCode,
|
||
|
IN PVOID pInBuffer,
|
||
|
IN ULONG InBufferSize,
|
||
|
OUT PVOID pOutBuffer,
|
||
|
IN ULONG OutBufferSize,
|
||
|
OUT PULONG pBytesReturned )
|
||
|
{
|
||
|
NTSTATUS Status;
|
||
|
PSTACK pStack;
|
||
|
|
||
|
pStack = (PSTACK) pContext;
|
||
|
|
||
|
/*
|
||
|
* Call callback function to handle StackIoControl
|
||
|
*/
|
||
|
if ( pStack->pStackIoControlCallback ) {
|
||
|
|
||
|
/*
|
||
|
* Unlock critical section
|
||
|
*/
|
||
|
pStack->RefCount++;
|
||
|
UNLOCK( &pStack->CritSec );
|
||
|
|
||
|
Status = pStack->pStackIoControlCallback(
|
||
|
pStack->pCallbackContext,
|
||
|
pStack,
|
||
|
IoControlCode,
|
||
|
pInBuffer,
|
||
|
InBufferSize,
|
||
|
pOutBuffer,
|
||
|
OutBufferSize,
|
||
|
pBytesReturned );
|
||
|
|
||
|
/*
|
||
|
* Re-lock critical section
|
||
|
*/
|
||
|
LOCK( &pStack->CritSec );
|
||
|
_DecrementStackRef( pStack );
|
||
|
|
||
|
} else {
|
||
|
|
||
|
Status = _IcaStackIoControlWorker( pStack,
|
||
|
IoControlCode,
|
||
|
pInBuffer,
|
||
|
InBufferSize,
|
||
|
pOutBuffer,
|
||
|
OutBufferSize,
|
||
|
pBytesReturned );
|
||
|
}
|
||
|
|
||
|
return( Status );
|
||
|
}
|
||
|
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* _IcaStackIoControlWorker
|
||
|
*
|
||
|
* Private worker interface to an ICA stack
|
||
|
*
|
||
|
* ENTRY:
|
||
|
* pStack (input)
|
||
|
* pointer to ICA stack structure
|
||
|
* IoControlCode (input)
|
||
|
* I/O control code
|
||
|
* pInBuffer (input)
|
||
|
* Pointer to input parameters
|
||
|
* InBufferSize (input)
|
||
|
* Size of pInBuffer
|
||
|
* pOutBuffer (output)
|
||
|
* Pointer to output buffer
|
||
|
* OutBufferSize (input)
|
||
|
* Size of pOutBuffer
|
||
|
* pBytesReturned (output)
|
||
|
* Pointer to number of bytes returned
|
||
|
*
|
||
|
* EXIT:
|
||
|
* STATUS_SUCCESS - Success
|
||
|
* other - Error return code
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
|
||
|
NTSTATUS
|
||
|
_IcaStackIoControlWorker( IN PSTACK pStack,
|
||
|
IN ULONG IoControlCode,
|
||
|
IN PVOID pInBuffer,
|
||
|
IN ULONG InBufferSize,
|
||
|
OUT PVOID pOutBuffer,
|
||
|
IN ULONG OutBufferSize,
|
||
|
OUT PULONG pBytesReturned )
|
||
|
{
|
||
|
NTSTATUS Status;
|
||
|
|
||
|
if ( pStack->pCdIoControl ) {
|
||
|
|
||
|
/*
|
||
|
* Call connection driver, CD will call ICA device driver
|
||
|
*/
|
||
|
Status = (*pStack->pCdIoControl)( pStack->pCdContext,
|
||
|
IoControlCode,
|
||
|
pInBuffer,
|
||
|
InBufferSize,
|
||
|
pOutBuffer,
|
||
|
OutBufferSize,
|
||
|
pBytesReturned );
|
||
|
|
||
|
if ( pStack->fClosing && (IoControlCode != IOCTL_ICA_STACK_POP) )
|
||
|
Status = STATUS_CTX_CLOSE_PENDING;
|
||
|
|
||
|
} else {
|
||
|
|
||
|
/*
|
||
|
* Unlock critical section
|
||
|
*/
|
||
|
pStack->RefCount++;
|
||
|
UNLOCK( &pStack->CritSec );
|
||
|
|
||
|
/*
|
||
|
* Call ICA device driver directly
|
||
|
* - this stack does not have a connection driver
|
||
|
*/
|
||
|
Status = IcaIoControl( pStack->hStack,
|
||
|
IoControlCode,
|
||
|
pInBuffer,
|
||
|
InBufferSize,
|
||
|
pOutBuffer,
|
||
|
OutBufferSize,
|
||
|
pBytesReturned );
|
||
|
|
||
|
/*
|
||
|
* Re-lock critical section
|
||
|
*/
|
||
|
LOCK( &pStack->CritSec );
|
||
|
_DecrementStackRef( pStack );
|
||
|
}
|
||
|
|
||
|
return( Status );
|
||
|
}
|
||
|
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* _IcaPushStackAndCreateEndpoint
|
||
|
*
|
||
|
* Load and create stack endpoint
|
||
|
*
|
||
|
*
|
||
|
* ENTRY:
|
||
|
* pStack (input)
|
||
|
* pointer to ICA stack structure
|
||
|
* pWinStationName (input)
|
||
|
* registry name of WinStation
|
||
|
* pWinStationConfig (input)
|
||
|
* pointer to winstation registry configuration data
|
||
|
* pInAddress (input)
|
||
|
* pointer to address to use (optional)
|
||
|
* pOutAddress (output)
|
||
|
* pointer to location to return final address (optional)
|
||
|
*
|
||
|
*
|
||
|
* EXIT:
|
||
|
* STATUS_SUCCESS - Success
|
||
|
* other - Error return code
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
|
||
|
NTSTATUS
|
||
|
_IcaPushStackAndCreateEndpoint( IN PSTACK pStack,
|
||
|
IN PWINSTATIONNAME pWinStationName,
|
||
|
IN PWINSTATIONCONFIG2 pWinStationConfig,
|
||
|
IN PICA_STACK_ADDRESS pInAddress,
|
||
|
OUT PICA_STACK_ADDRESS pOutAddress )
|
||
|
{
|
||
|
ULONG BytesReturned;
|
||
|
NTSTATUS Status;
|
||
|
|
||
|
ASSERTLOCK( &pStack->CritSec );
|
||
|
|
||
|
/*
|
||
|
* Load template Stack
|
||
|
*/
|
||
|
Status = _IcaPushStack( pStack, pWinStationName, pWinStationConfig );
|
||
|
if ( !NT_SUCCESS(Status) ) {
|
||
|
goto badpush;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Open the transport driver endpoint
|
||
|
*/
|
||
|
Status = _IcaStackIoControl( pStack,
|
||
|
IOCTL_ICA_STACK_CREATE_ENDPOINT,
|
||
|
pInAddress,
|
||
|
pInAddress ? sizeof(*pInAddress) : 0,
|
||
|
pOutAddress,
|
||
|
pOutAddress ? sizeof(*pOutAddress) : 0,
|
||
|
&BytesReturned );
|
||
|
if ( !NT_SUCCESS(Status) ) {
|
||
|
goto badendpoint;
|
||
|
}
|
||
|
|
||
|
|
||
|
TRACESTACK(( pStack, TC_ICAAPI, TT_API1, "TSAPI: _IcaPushStackAndCreateEndpoint, success\n" ));
|
||
|
return( STATUS_SUCCESS );
|
||
|
|
||
|
/*=============================================================================
|
||
|
== Error returns
|
||
|
=============================================================================*/
|
||
|
|
||
|
badendpoint:
|
||
|
/* pop all stack drivers */
|
||
|
_IcaPopStack( pStack );
|
||
|
|
||
|
badpush:
|
||
|
TRACESTACK(( pStack, TC_ICAAPI, TT_ERROR, "TSAPI: _IcaPushStackAndCreateEndpoint, 0x%x\n", Status ));
|
||
|
return( Status );
|
||
|
}
|
||
|
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* _IcaPushStackAndOpenEndpoint
|
||
|
*
|
||
|
* Load and open stack endpoint
|
||
|
*
|
||
|
*
|
||
|
* ENTRY:
|
||
|
*
|
||
|
* pStack (input)
|
||
|
* pointer to ICA stack structure
|
||
|
* pWinStationName (input)
|
||
|
* registry name of WinStation
|
||
|
* pWinStationConfig (input)
|
||
|
* pointer to winstation registry configuration data
|
||
|
* pEndpoint (input)
|
||
|
* Structure defining connection endpoint
|
||
|
* EndpointLength (input)
|
||
|
* Length of endpoint
|
||
|
*
|
||
|
* EXIT:
|
||
|
* STATUS_SUCCESS - Success
|
||
|
* other - Error return code
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
|
||
|
NTSTATUS
|
||
|
_IcaPushStackAndOpenEndpoint( IN PSTACK pStack,
|
||
|
IN PWINSTATIONNAME pWinStationName,
|
||
|
IN PWINSTATIONCONFIG2 pWinStationConfig,
|
||
|
IN PVOID pEndpoint,
|
||
|
IN ULONG EndpointLength )
|
||
|
{
|
||
|
NTSTATUS Status;
|
||
|
|
||
|
ASSERTLOCK( &pStack->CritSec );
|
||
|
|
||
|
/*
|
||
|
* Load the template stack again
|
||
|
*/
|
||
|
Status = _IcaPushStack( pStack, pWinStationName, pWinStationConfig );
|
||
|
if ( !NT_SUCCESS(Status) ) {
|
||
|
goto badpush;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Give open endpoint to the transport driver
|
||
|
*/
|
||
|
Status = _IcaStackIoControl( pStack,
|
||
|
IOCTL_ICA_STACK_OPEN_ENDPOINT,
|
||
|
pEndpoint,
|
||
|
EndpointLength,
|
||
|
NULL,
|
||
|
0,
|
||
|
NULL );
|
||
|
if ( !NT_SUCCESS(Status) ) {
|
||
|
goto badendpoint;
|
||
|
}
|
||
|
|
||
|
TRACESTACK(( pStack, TC_ICAAPI, TT_API1, "TSAPI: _IcaPushStackAndOpenEndpoint, success\n" ));
|
||
|
return( STATUS_SUCCESS );
|
||
|
|
||
|
/*=============================================================================
|
||
|
== Error returns
|
||
|
=============================================================================*/
|
||
|
|
||
|
badendpoint:
|
||
|
/* pop all stack drivers */
|
||
|
_IcaPopStack( pStack );
|
||
|
|
||
|
badpush:
|
||
|
TRACESTACK(( pStack, TC_ICAAPI, TT_ERROR, "TSAPI: _IcaPushStackAndOpenEndpoint, 0x%x\n", Status ));
|
||
|
return( Status );
|
||
|
}
|
||
|
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* _IcaPushStack
|
||
|
*
|
||
|
* Load initial stack
|
||
|
*
|
||
|
* stack push for each stack driver
|
||
|
* in order td - pd - wd
|
||
|
*
|
||
|
* ENTRY:
|
||
|
* pStack (input)
|
||
|
* pointer to ICA stack structure
|
||
|
* pWinStationName (input)
|
||
|
* registry name of WinStation
|
||
|
* pWinStationConfig (input)
|
||
|
* pointer to winstation registry configuration data
|
||
|
*
|
||
|
* EXIT:
|
||
|
* STATUS_SUCCESS - Success
|
||
|
* other - Error return code
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
|
||
|
NTSTATUS
|
||
|
_IcaPushStack( IN PSTACK pStack,
|
||
|
IN PWINSTATIONNAME pWinStationName,
|
||
|
IN PWINSTATIONCONFIG2 pWinStationConfig )
|
||
|
{
|
||
|
PPDCONFIG pPdConfig;
|
||
|
NTSTATUS Status;
|
||
|
ULONG i;
|
||
|
|
||
|
ASSERTLOCK( &pStack->CritSec );
|
||
|
|
||
|
/*
|
||
|
* Load and open connection driver
|
||
|
*/
|
||
|
Status = _CdOpen( pStack, pWinStationConfig );
|
||
|
if ( !NT_SUCCESS(Status) )
|
||
|
goto badcdopen;
|
||
|
|
||
|
/*
|
||
|
* Load PD(s)
|
||
|
*/
|
||
|
pPdConfig = &pWinStationConfig->Pd[0];
|
||
|
for ( i = 0; i < MAX_PDCONFIG; i++, pPdConfig++ ) {
|
||
|
|
||
|
if ( pPdConfig->Create.SdClass == SdNone )
|
||
|
break;
|
||
|
|
||
|
/*
|
||
|
* Do the push.
|
||
|
*/
|
||
|
Status = _IcaPushPd( pStack,
|
||
|
pWinStationName,
|
||
|
pWinStationConfig,
|
||
|
pPdConfig->Create.PdDLL,
|
||
|
pPdConfig );
|
||
|
if ( !NT_SUCCESS( Status ) ) {
|
||
|
goto badpdpush;
|
||
|
}
|
||
|
|
||
|
if ( pStack->fClosing ) {
|
||
|
goto stackclosing;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Push the WD.
|
||
|
*/
|
||
|
Status = _IcaPushWd( pStack, pWinStationName, pWinStationConfig );
|
||
|
if ( !NT_SUCCESS(Status) )
|
||
|
goto badwdpush;
|
||
|
|
||
|
if ( pStack->fClosing ) {
|
||
|
goto stackclosing;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Set stack loaded flag
|
||
|
*/
|
||
|
pStack->fStackLoaded = TRUE;
|
||
|
|
||
|
TRACESTACK(( pStack, TC_ICAAPI, TT_API1, "TSAPI: _IcaPushStack, success\n" ));
|
||
|
return( STATUS_SUCCESS );
|
||
|
|
||
|
/*=============================================================================
|
||
|
== Error returns
|
||
|
=============================================================================*/
|
||
|
|
||
|
badwdpush:
|
||
|
badpdpush:
|
||
|
/* pop all stack drivers */
|
||
|
_IcaPopStack( pStack );
|
||
|
|
||
|
badcdopen:
|
||
|
TRACESTACK(( pStack, TC_ICAAPI, TT_ERROR, "TSAPI: _IcaPushStack, 0x%x\n", Status ));
|
||
|
return( Status );
|
||
|
|
||
|
stackclosing:
|
||
|
/*
|
||
|
* Unload all stack drivers
|
||
|
*/
|
||
|
while ( _IcaPopSd( pStack ) == STATUS_SUCCESS ) {;}
|
||
|
|
||
|
return( STATUS_CTX_CLOSE_PENDING );
|
||
|
}
|
||
|
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* _IcaPushPd
|
||
|
*
|
||
|
* Push a PD module.
|
||
|
*
|
||
|
* ENTRY:
|
||
|
* pStack (input)
|
||
|
* pointer to ICA stack structure
|
||
|
* pWinStationName (input)
|
||
|
* registry name of WinStation
|
||
|
* pWinStationConfig (input)
|
||
|
* pointer to winstation registry configuration data
|
||
|
* pDllName (input)
|
||
|
* Name of module to push
|
||
|
* pPdConfig (input)
|
||
|
* pointer to configuration data
|
||
|
*
|
||
|
* EXIT:
|
||
|
* STATUS_SUCCESS - Success
|
||
|
* other - Error return code
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
|
||
|
NTSTATUS
|
||
|
_IcaPushPd( IN PSTACK pStack,
|
||
|
IN PWINSTATIONNAME pWinStationName,
|
||
|
IN PWINSTATIONCONFIG2 pWinStationConfig,
|
||
|
IN PDLLNAME pDllName,
|
||
|
IN PPDCONFIG pPdConfig )
|
||
|
{
|
||
|
ICA_STACK_PUSH IcaStackPush;
|
||
|
NTSTATUS Status;
|
||
|
|
||
|
ASSERTLOCK( &pStack->CritSec );
|
||
|
|
||
|
TRACESTACK(( pStack, TC_ICAAPI, TT_API1, "TSAPI: _IcaPushPd, %S\n", pDllName ));
|
||
|
|
||
|
memset( &IcaStackPush, 0, sizeof(IcaStackPush) );
|
||
|
|
||
|
IcaStackPush.StackModuleType = Stack_Module_Pd;
|
||
|
|
||
|
ASSERT( pDllName[0] );
|
||
|
|
||
|
memcpy( IcaStackPush.StackModuleName, pDllName,
|
||
|
sizeof( IcaStackPush.StackModuleName ) );
|
||
|
|
||
|
#ifndef _HYDRA_
|
||
|
// wcscat( IcaStackPush.StackModuleName, ICA_SD_MODULE_EXTENTION );
|
||
|
#endif
|
||
|
|
||
|
memcpy( IcaStackPush.OEMId,
|
||
|
pWinStationConfig->Config.OEMId,
|
||
|
sizeof(pWinStationConfig->Config.OEMId) );
|
||
|
|
||
|
IcaStackPush.WdConfig = pWinStationConfig->Wd;
|
||
|
IcaStackPush.PdConfig = *pPdConfig;
|
||
|
|
||
|
memcpy( IcaStackPush.WinStationRegName,
|
||
|
pWinStationName,
|
||
|
sizeof(IcaStackPush.WinStationRegName) );
|
||
|
|
||
|
Status = _IcaStackIoControl( pStack,
|
||
|
IOCTL_ICA_STACK_PUSH,
|
||
|
&IcaStackPush,
|
||
|
sizeof( IcaStackPush ),
|
||
|
NULL,
|
||
|
0,
|
||
|
NULL );
|
||
|
|
||
|
TRACESTACK(( pStack, TC_ICAAPI, TT_API1, "TSAPI: _IcaPushPd, %S, 0x%x\n", pDllName, Status ));
|
||
|
return( Status );
|
||
|
}
|
||
|
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* _IcaPushWd
|
||
|
*
|
||
|
* Push a WD module.
|
||
|
*
|
||
|
* ENTRY:
|
||
|
* pStack (input)
|
||
|
* pointer to ICA stack structure
|
||
|
* pWinStationName (input)
|
||
|
* registry name of WinStation
|
||
|
* pWinStationConfig (input)
|
||
|
* pointer to winstation registry configuration data
|
||
|
*
|
||
|
* EXIT:
|
||
|
* STATUS_SUCCESS - Success
|
||
|
* other - Error return code
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
|
||
|
NTSTATUS
|
||
|
_IcaPushWd( IN PSTACK pStack,
|
||
|
IN PWINSTATIONNAME pWinStationName,
|
||
|
IN PWINSTATIONCONFIG2 pWinStationConfig )
|
||
|
{
|
||
|
ICA_STACK_PUSH IcaStackPush;
|
||
|
NTSTATUS Status;
|
||
|
|
||
|
ASSERTLOCK( &pStack->CritSec );
|
||
|
|
||
|
TRACESTACK(( pStack, TC_ICAAPI, TT_API1, "TSAPI: _IcaPushWd, %S\n", pWinStationConfig->Wd.WdDLL ));
|
||
|
|
||
|
memset( &IcaStackPush, 0, sizeof(IcaStackPush) );
|
||
|
|
||
|
IcaStackPush.StackModuleType = Stack_Module_Wd;
|
||
|
|
||
|
memcpy( IcaStackPush.StackModuleName, pWinStationConfig->Wd.WdDLL,
|
||
|
sizeof( IcaStackPush.StackModuleName ) );
|
||
|
|
||
|
#ifndef _HYDRA_
|
||
|
//wcscat( IcaStackPush.StackModuleName, ICA_SD_MODULE_EXTENTION );
|
||
|
#endif
|
||
|
|
||
|
memcpy( IcaStackPush.OEMId,
|
||
|
pWinStationConfig->Config.OEMId,
|
||
|
sizeof(pWinStationConfig->Config.OEMId) );
|
||
|
|
||
|
IcaStackPush.WdConfig = pWinStationConfig->Wd;
|
||
|
IcaStackPush.PdConfig = pWinStationConfig->Pd[0];
|
||
|
|
||
|
memcpy( IcaStackPush.WinStationRegName,
|
||
|
pWinStationName,
|
||
|
sizeof(IcaStackPush.WinStationRegName) );
|
||
|
|
||
|
Status = _IcaStackIoControl( pStack,
|
||
|
IOCTL_ICA_STACK_PUSH,
|
||
|
&IcaStackPush,
|
||
|
sizeof( IcaStackPush ),
|
||
|
NULL,
|
||
|
0,
|
||
|
NULL );
|
||
|
|
||
|
TRACESTACK(( pStack, TC_ICAAPI, TT_API1, "TSAPI: _IcaPushWd, %S, 0x%x\n", pWinStationConfig->Wd.WdDLL, Status ));
|
||
|
return( Status );
|
||
|
}
|
||
|
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* _IcaPopStack
|
||
|
*
|
||
|
* Pop all the stack drivers
|
||
|
*
|
||
|
* ENTRY:
|
||
|
* pStack (input)
|
||
|
* pointer to ICA stack structure
|
||
|
*
|
||
|
* EXIT:
|
||
|
* nothing
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
|
||
|
void
|
||
|
_IcaPopStack( IN PSTACK pStack )
|
||
|
{
|
||
|
ASSERTLOCK( &pStack->CritSec );
|
||
|
|
||
|
/*
|
||
|
* If another thread is doing the unload, then nothing else to do.
|
||
|
*/
|
||
|
if ( pStack->fUnloading )
|
||
|
return;
|
||
|
pStack->fUnloading = TRUE;
|
||
|
|
||
|
/*
|
||
|
* Unload all stack drivers
|
||
|
*/
|
||
|
while ( _IcaPopSd( pStack ) == STATUS_SUCCESS ) {
|
||
|
;
|
||
|
}
|
||
|
|
||
|
TRACESTACK(( pStack, TC_ICAAPI, TT_API1, "TSAPI: _IcaPopStack all stack drivers unloaded\n" ));
|
||
|
|
||
|
/*
|
||
|
* Release CD threads
|
||
|
*/
|
||
|
(void) _IcaStackIoControl( pStack,
|
||
|
IOCTL_ICA_STACK_CD_CANCEL_IO,
|
||
|
NULL, 0, NULL, 0, NULL );
|
||
|
|
||
|
/*
|
||
|
* Wait for all other references (besides our own) to go away
|
||
|
*/
|
||
|
pStack->RefCount++;
|
||
|
waitagain:
|
||
|
while ( pStack->RefCount > 1 ) {
|
||
|
|
||
|
TRACESTACK(( pStack, TC_ICAAPI, TT_API1, "TSAPI: _IcaPopStack: waiting for refcount %d\n", pStack->RefCount ));
|
||
|
|
||
|
pStack->hUnloadEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
|
||
|
ASSERT( pStack->hUnloadEvent );
|
||
|
|
||
|
UNLOCK( &pStack->CritSec );
|
||
|
(void) WaitForSingleObject( pStack->hUnloadEvent, INFINITE );
|
||
|
LOCK( &pStack->CritSec );
|
||
|
|
||
|
// NOTE: seems to me that between being notified and locking the
|
||
|
// stack, some other thread could have locked the stack and bumped
|
||
|
// the ref count. no breaks have ever been hit, though.
|
||
|
if (pStack->RefCount > 1) {
|
||
|
goto waitagain;
|
||
|
}
|
||
|
|
||
|
CloseHandle( pStack->hUnloadEvent );
|
||
|
pStack->hUnloadEvent = NULL;
|
||
|
}
|
||
|
_DecrementStackRef( pStack );
|
||
|
|
||
|
/*
|
||
|
* Unload connection driver
|
||
|
*/
|
||
|
_CdClose( pStack );
|
||
|
|
||
|
/*
|
||
|
* Clear stack loaded flag
|
||
|
*/
|
||
|
pStack->fStackLoaded = FALSE;
|
||
|
pStack->fUnloading = FALSE;
|
||
|
|
||
|
TRACESTACK(( pStack, TC_ICAAPI, TT_API1, "TSAPI: _IcaPopStack\n" ));
|
||
|
}
|
||
|
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* _IcaPopSd
|
||
|
*
|
||
|
* Pop a stack driver module (wd or pd)
|
||
|
*
|
||
|
* ENTRY:
|
||
|
* pStack (input)
|
||
|
* pointer to ICA stack structure
|
||
|
*
|
||
|
* EXIT:
|
||
|
* STATUS_SUCCESS - Success
|
||
|
* other - Error return code
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
|
||
|
NTSTATUS
|
||
|
_IcaPopSd( IN PSTACK pStack )
|
||
|
{
|
||
|
NTSTATUS Status;
|
||
|
|
||
|
ASSERTLOCK( &pStack->CritSec );
|
||
|
|
||
|
Status = _IcaStackIoControl( pStack,
|
||
|
IOCTL_ICA_STACK_POP,
|
||
|
NULL,
|
||
|
0,
|
||
|
NULL,
|
||
|
0,
|
||
|
NULL );
|
||
|
|
||
|
TRACESTACK(( pStack, TC_ICAAPI, TT_API1, "TSAPI: _IcaPopSd, 0x%x\n", Status ));
|
||
|
return( Status );
|
||
|
}
|
||
|
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* _IcaStackWaitForIca
|
||
|
*
|
||
|
* Wait for ICA Detect string
|
||
|
*
|
||
|
* ENTRY:
|
||
|
* pStack (input)
|
||
|
* pointer to ICA stack structure
|
||
|
* pWinStationConfig (input/output)
|
||
|
* pointer to winstation registry configuration data
|
||
|
* pfStackModified (output)
|
||
|
* Pointer to stack modified flag
|
||
|
*
|
||
|
* EXIT:
|
||
|
* STATUS_SUCCESS - Success
|
||
|
* other - Error return code
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
|
||
|
NTSTATUS
|
||
|
_IcaStackWaitForIca( IN PSTACK pStack,
|
||
|
IN OUT PWINSTATIONCONFIG2 pWinStationConfig,
|
||
|
OUT BOOLEAN * pfStackModified )
|
||
|
{
|
||
|
ICA_STACK_CONFIG IcaStackConfig;
|
||
|
PPDCONFIG pPdConfig;
|
||
|
NTSTATUS Status;
|
||
|
ULONG cbReturned;
|
||
|
ULONG i;
|
||
|
|
||
|
ASSERTLOCK( &pStack->CritSec );
|
||
|
|
||
|
/*
|
||
|
* Initialize flag
|
||
|
*/
|
||
|
*pfStackModified = FALSE;
|
||
|
|
||
|
/*
|
||
|
* Wait for ICA Detect string from client
|
||
|
*/
|
||
|
Status = _IcaStackIoControl( pStack,
|
||
|
IOCTL_ICA_STACK_WAIT_FOR_ICA,
|
||
|
NULL,
|
||
|
0,
|
||
|
&IcaStackConfig,
|
||
|
sizeof(IcaStackConfig),
|
||
|
&cbReturned );
|
||
|
if ( !NT_SUCCESS(Status) ) {
|
||
|
goto baddetect;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* If ICA Detect returned any stack information, then update it
|
||
|
*/
|
||
|
if ( cbReturned > 0 ) {
|
||
|
|
||
|
ASSERT( FALSE );
|
||
|
#ifdef notdef
|
||
|
|
||
|
/*
|
||
|
* this path has not been tested
|
||
|
*
|
||
|
* Return configuration data
|
||
|
* -- skip transport driver (index 0)
|
||
|
*/
|
||
|
for ( i = 0; i < (MAX_PDCONFIG-1); i++ ) {
|
||
|
|
||
|
pPdConfig = &pWinStationConfig->Pd[i+1];
|
||
|
|
||
|
memset( pPdConfig, 0, sizeof(PDCONFIG) );
|
||
|
|
||
|
if ( IcaStackConfig.SdClass[i] == SdNone )
|
||
|
break;
|
||
|
|
||
|
pPdConfig->Create.SdClass = IcaStackConfig.SdClass[i];
|
||
|
memcpy( pPdConfig->Create.PdDLL, IcaStackConfig.SdDLL[i], sizeof(DLLNAME) );
|
||
|
}
|
||
|
|
||
|
if ( IcaStackConfig.WdDLL[0] )
|
||
|
memcpy( pWinStationConfig->Wd.WdDLL, IcaStackConfig.WdDLL, sizeof(DLLNAME) );
|
||
|
|
||
|
/*
|
||
|
* Set modify flag
|
||
|
*/
|
||
|
*pfStackModified = TRUE;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
TRACESTACK(( pStack, TC_ICAAPI, TT_API1, "TSAPI: _IcaWaitForIca, success\n" ));
|
||
|
return( STATUS_SUCCESS );
|
||
|
|
||
|
/*=============================================================================
|
||
|
== Error returns
|
||
|
=============================================================================*/
|
||
|
|
||
|
baddetect:
|
||
|
TRACESTACK(( pStack, TC_ICAAPI, TT_ERROR, "TSAPI: _IcaWaitForIca, 0x%x\n", Status ));
|
||
|
return( Status );
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* _DecrementStackRef
|
||
|
*
|
||
|
* decrement stack reference
|
||
|
*
|
||
|
* ENTRY:
|
||
|
* pStack (input)
|
||
|
* pointer to ICA stack structure
|
||
|
*
|
||
|
* EXIT:
|
||
|
* nothing
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
|
||
|
void
|
||
|
_DecrementStackRef( IN PSTACK pStack )
|
||
|
{
|
||
|
pStack->RefCount--;
|
||
|
|
||
|
if ( pStack->RefCount == 1 && pStack->hUnloadEvent ) {
|
||
|
SetEvent( pStack->hUnloadEvent );
|
||
|
|
||
|
} else if ( pStack->RefCount == 0 && pStack->hCloseEvent ) {
|
||
|
SetEvent( pStack->hCloseEvent );
|
||
|
}
|
||
|
}
|