|
|
/*************************************************************************
* 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 ); } }
|