Windows-Server-2003/termsrv/icaapi/stack.c

2473 lines
68 KiB
C
Raw Permalink Normal View History

2024-08-04 01:28:15 +02:00
/*************************************************************************
* 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 );
}
/****************************************************************************
*
* IcaStackQueryLocalAddress
*
* Load template stack and query RDP-Enabled local IP Address
*
*
*
* 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)
* pLocalIPAddress (output)
* Pointer to buffer to return RDP-Enabled Local IP Address
* BufferLength (input)
* length of input data buffer
* pEndpointLength (output)
* pointer to return actual length of LocaIPAddress
*
* EXIT:
* STATUS_SUCCESS - Success
* other - Error return code
*
****************************************************************************/
NTSTATUS
IcaStackQueryLocalAddress( IN HANDLE pContext,
IN PWINSTATIONNAME pWinStationName,
IN PWINSTATIONCONFIG2 pWinStationConfig,
IN PICA_STACK_ADDRESS pAddress,
OUT PVOID pLocalIPAddress,
IN ULONG BufferLength,
OUT PULONG pLocalIPAddressLength )
{
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;
}
Status = _IcaStackIoControl( pStack,
IOCTL_ICA_STACK_QUERY_LOCALADDRESS,
NULL,
0,
pLocalIPAddress,
BufferLength,
pLocalIPAddressLength );
if ( !NT_SUCCESS(Status) )
goto badquery;
TRACESTACK(( pContext, TC_ICAAPI, TT_API1, "TSAPI: IcaStackQueryLocalAddress, 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.
*/
badquery:
if ( !fStackLoaded ) {
_IcaPopStack( pContext );
}
badcreate:
*pLocalIPAddressLength = 0;
memset( pLocalIPAddress, 0, BufferLength );
TRACESTACK(( pContext, TC_ICAAPI, TT_ERROR, "TSAPI: IcaStackQueryLocalAddress, 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 );
}
}