|
|
/*************************************************************************
* * wininit.c * * Window station init and destroy routines * * Copyright Microsoft Corporation, 1998 * * *************************************************************************/
/*
* Includes */ #include "precomp.h"
#pragma hdrstop
/*
* Local data */ #define LOGOFF_TIMER 120000L
#define MODULE_SIZE 1024 /* Default size for retrive of module data */
#define VDDATA_LENGTH 1024
/*
* Internal Procedures */ VOID StartLogonTimers( PWINSTATION ); VOID IdleTimeout( ULONG ); VOID LogonTimeout( ULONG ); VOID IdleLogoffTimeout( ULONG ); VOID LogoffTimeout( ULONG );
/*******************************************************************************
* * StartLogonTimers * * This routine is called when an user is logged on. * Timers are started for idle input and total logon time. * * ENTRY: * None. * * EXIT: * None. * ******************************************************************************/
VOID StartLogonTimers( PWINSTATION pWinStation ) { int Status; ULONG Timer; BOOL bValidHelpSession;
// for Session0 and any console sessions, timeouts don't make sense
if ( ( pWinStation->LogonId != 0 ) && ( pWinStation->LogonId != USER_SHARED_DATA->ActiveConsoleId ) ) {
if( TSIsSessionHelpSession(pWinStation, &bValidHelpSession) ) { ASSERT( TRUE == bValidHelpSession ); return; }
if ( Timer = pWinStation->Config.Config.User.MaxIdleTime ) { if ( !pWinStation->fIdleTimer ) { Status = IcaTimerCreate( 0, &pWinStation->hIdleTimer ); if ( NT_SUCCESS( Status ) ) pWinStation->fIdleTimer = TRUE; else DBGPRINT(( "StartLogonTimers - failed to create idle timer \n" )); } if ( pWinStation->fIdleTimer ) IcaTimerStart( pWinStation->hIdleTimer, IdleTimeout, LongToPtr( pWinStation->LogonId ), Timer ); }
if ( Timer = pWinStation->Config.Config.User.MaxConnectionTime ) { if ( !pWinStation->fLogonTimer ) { Status = IcaTimerCreate( 0, &pWinStation->hLogonTimer ); if ( NT_SUCCESS( Status ) ) pWinStation->fLogonTimer = TRUE; else DBGPRINT(( "StartLogonTimers - failed to create logon timer \n" )); } if ( pWinStation->fLogonTimer ) IcaTimerStart( pWinStation->hLogonTimer, LogonTimeout, LongToPtr( pWinStation->LogonId ), Timer ); } } }
/*******************************************************************************
* * IdleTimeout * * This routine is called when the idle timer expires. * Send the user a warning message and start timer to logoff in 2 minutes. * * ENTRY: * LogonId * * EXIT: * None. * ******************************************************************************/
VOID IdleTimeout( ULONG LogonId ) { LARGE_INTEGER liT; ULONG ulTimeDelta; ICA_STACK_LAST_INPUT_TIME Ica_Stack_Last_Input_Time; NTSTATUS Status; ULONG cbReturned; PWINSTATION pWinStation; WINSTATION_APIMSG msg;
pWinStation = FindWinStationById( LogonId, FALSE );
if ( !pWinStation ) return;
if ( !pWinStation->hStack ) goto done;
if ( !pWinStation->fIdleTimer ) goto done;
// Check for availability
if ( pWinStation->pWsx && pWinStation->pWsx->pWsxIcaStackIoControl ) {
Status = pWinStation->pWsx->pWsxIcaStackIoControl( pWinStation->pWsxContext, pWinStation->hIca, pWinStation->hStack, IOCTL_ICA_STACK_QUERY_LAST_INPUT_TIME, NULL, 0, &Ica_Stack_Last_Input_Time, sizeof( Ica_Stack_Last_Input_Time ), &cbReturned ); } else { Status = STATUS_INVALID_PARAMETER; }
if ( !NT_SUCCESS( Status ) ) { goto done; }
/*
* Check if there was input during the idle time */ NtQuerySystemTime( &liT ); // calculate delta in time & convert from 100ns unit to milliseconds
liT = RtlExtendedLargeIntegerDivide( RtlLargeIntegerSubtract( liT, Ica_Stack_Last_Input_Time.LastInputTime ), 10000, NULL ); ulTimeDelta = (ULONG)liT.LowTime;
TRACE((hTrace,TC_ICASRV,TT_API1, "IdleTimeout: delta = %d, max idle = %d\n", ulTimeDelta, pWinStation->Config.Config.User.MaxIdleTime ));
if ( ulTimeDelta < pWinStation->Config.Config.User.MaxIdleTime ) { IcaTimerStart( pWinStation->hIdleTimer, IdleTimeout, LongToPtr( LogonId ), pWinStation->Config.Config.User.MaxIdleTime - ulTimeDelta ); } else { TCHAR szTitle[128]; TCHAR szMsg[256]; int cchTitle, cchMessage;
IcaTimerStart( pWinStation->hIdleTimer, IdleLogoffTimeout, LongToPtr( LogonId ), LOGOFF_TIMER );
if ( !(cchTitle = LoadString(hModuleWin, STR_CITRIX_IDLE_TITLE, szTitle, sizeof(szTitle)/sizeof(TCHAR))) ) goto done; if ( pWinStation->Config.Config.User.fResetBroken ) {
if ( !(cchMessage = LoadString(hModuleWin, STR_CITRIX_IDLE_MSG_LOGOFF, szMsg, sizeof(szMsg)/sizeof(TCHAR)) )) goto done; } else { if ( !(cchMessage = LoadString(hModuleWin, STR_CITRIX_IDLE_MSG_DISCON, szMsg, sizeof(szMsg)/sizeof(TCHAR)) )) goto done;
}
msg.u.SendMessage.pTitle = szTitle; msg.u.SendMessage.TitleLength = (cchTitle+1) * sizeof(TCHAR); msg.u.SendMessage.pMessage = szMsg; msg.u.SendMessage.MessageLength = (cchMessage+1) * sizeof(TCHAR); msg.u.SendMessage.Style = MB_OK | MB_ICONSTOP; msg.u.SendMessage.Timeout = (ULONG)LOGOFF_TIMER/1000; msg.u.SendMessage.Response = 0; msg.u.SendMessage.DoNotWait = TRUE; msg.u.SendMessage.DoNotWaitForCorrectDesktop = FALSE; // since we dont care abou response, or message delievery status;
msg.u.SendMessage.pStatus = NULL; msg.u.SendMessage.pResponse = NULL; msg.u.SendMessage.hEvent = NULL;
msg.ApiNumber = SMWinStationDoMessage; Status = SendWinStationCommand( pWinStation, &msg, 0 );
} done: ReleaseWinStation( pWinStation ); }
/*******************************************************************************
* * LogonTimeout * * This routine is called when the logon timer expires. * Send the user a warning message and start timer to logoff in 2 minutes. * * ENTRY: * LogonId * * EXIT: * None. * ******************************************************************************/
VOID LogonTimeout( ULONG LogonId ) { TCHAR szTitle[128]; TCHAR szMsg[256]; PWINSTATION pWinStation; NTSTATUS Status; WINSTATION_APIMSG msg; int cchTitle, cchMsg;
pWinStation = FindWinStationById( LogonId, FALSE );
if ( !pWinStation ) return;
if ( !pWinStation->fLogonTimer) goto done;
if ( !(cchTitle = LoadString(hModuleWin, STR_CITRIX_LOGON_TITLE, szTitle, sizeof(szTitle)/sizeof(TCHAR)) )) goto done; if ( pWinStation->Config.Config.User.fResetBroken ) { if ( !(cchMsg = LoadString(hModuleWin, STR_CITRIX_LOGON_MSG_LOGOFF, szMsg, sizeof(szMsg)/sizeof(TCHAR)) )) goto done; } else { if ( !(cchMsg = LoadString(hModuleWin, STR_CITRIX_LOGON_MSG_DISCON, szMsg, sizeof(szMsg)/sizeof(TCHAR)) )) goto done; }
msg.u.SendMessage.pTitle = szTitle; msg.u.SendMessage.TitleLength = ( cchTitle+1 ) * sizeof(TCHAR); msg.u.SendMessage.pMessage = szMsg; msg.u.SendMessage.MessageLength = ( cchMsg+1 ) * sizeof(TCHAR); msg.u.SendMessage.Style = MB_OK | MB_ICONSTOP; msg.u.SendMessage.Timeout = (ULONG)LOGOFF_TIMER/1000; msg.u.SendMessage.Response = 0; msg.u.SendMessage.DoNotWait = TRUE; msg.u.SendMessage.DoNotWaitForCorrectDesktop = FALSE;
// since we dont care abou response, or message delievery status;
msg.u.SendMessage.pStatus = NULL; msg.u.SendMessage.pResponse = NULL; msg.u.SendMessage.hEvent = NULL;
msg.ApiNumber = SMWinStationDoMessage; Status = SendWinStationCommand( pWinStation, &msg, 0 );
IcaTimerStart( pWinStation->hLogonTimer, LogoffTimeout, LongToPtr( LogonId ), LOGOFF_TIMER ); if (pWinStation->fIdleTimer) { pWinStation->fIdleTimer = FALSE; IcaTimerClose( pWinStation->hIdleTimer ); } done: ReleaseWinStation( pWinStation ); }
/*******************************************************************************
* * IdleLogoffTimeout * * This routine is called when the logoff timer expires. * Check for input before logging user off * * ENTRY: * LogonId * * EXIT: * None. * ******************************************************************************/
VOID IdleLogoffTimeout( ULONG LogonId ) { LARGE_INTEGER liT; ULONG ulTimeDelta; ICA_STACK_LAST_INPUT_TIME Ica_Stack_Last_Input_Time; NTSTATUS Status; ULONG cbReturned; PWINSTATION pWinStation;
pWinStation = FindWinStationById( LogonId, FALSE );
if ( !pWinStation ) return;
if ( !pWinStation->hStack ) goto done;
if ( !pWinStation->fIdleTimer ) goto done;
// Check for availability
if ( pWinStation->pWsx && pWinStation->pWsx->pWsxIcaStackIoControl ) {
Status = pWinStation->pWsx->pWsxIcaStackIoControl( pWinStation->pWsxContext, pWinStation->hIca, pWinStation->hStack, IOCTL_ICA_STACK_QUERY_LAST_INPUT_TIME, NULL, 0, &Ica_Stack_Last_Input_Time, sizeof( Ica_Stack_Last_Input_Time ), &cbReturned ); } else { Status = STATUS_INVALID_PARAMETER; }
if ( !NT_SUCCESS( Status ) ) { goto done; }
NtQuerySystemTime( &liT ); liT = RtlExtendedLargeIntegerDivide( RtlLargeIntegerSubtract( liT, Ica_Stack_Last_Input_Time.LastInputTime ), 10000, NULL ); ulTimeDelta = (ULONG)liT.LowTime;
TRACE((hTrace,TC_ICASRV,TT_API1, "IdleTimeout: delta = %d, max idle = %d\n", ulTimeDelta, LOGOFF_TIMER ));
if ( ulTimeDelta < LOGOFF_TIMER ) { IcaTimerStart( pWinStation->hIdleTimer, IdleTimeout, LongToPtr( LogonId ), pWinStation->Config.Config.User.MaxIdleTime - ulTimeDelta ); } else LogoffTimeout( LogonId );
done: ReleaseWinStation( pWinStation ); }
/*******************************************************************************
* * LogoffTimeout * * This routine is called when the logoff timer expires. * Log user off and disconnect the winstation. * * ENTRY: * LogonId - LogonId to logout * * EXIT: * None. * ******************************************************************************/
VOID LogoffTimeout(ULONG LogonId) { PWINSTATION pWinStation;
pWinStation = FindWinStationById( LogonId, FALSE );
if ( !pWinStation ) return;
//
// Report disconnect reason back to client
//
if(pWinStation->WinStationName[0] && pWinStation->pWsx && pWinStation->pWsx->pWsxSetErrorInfo && pWinStation->pWsxContext) { ULONG discReason = 0; if(pWinStation->fIdleTimer) { discReason = TS_ERRINFO_IDLE_TIMEOUT; } else if(pWinStation->fLogonTimer) { discReason = TS_ERRINFO_LOGON_TIMEOUT; }
if(discReason) { pWinStation->pWsx->pWsxSetErrorInfo( pWinStation->pWsxContext, discReason, FALSE); //stack lock not held
} }
if ( pWinStation->Config.Config.User.fResetBroken ) { ReleaseWinStation( pWinStation ); QueueWinStationReset( LogonId ); } else { ReleaseWinStation( pWinStation ); QueueWinStationDisconnect( LogonId ); } }
/*******************************************************************************
* * DisconnectTimeout * * This routine is called when the disconnect timer expires. * Reset the winstation. * * ENTRY: * LogonId * * EXIT: * None. * ******************************************************************************/
VOID DisconnectTimeout( ULONG LogonId ) { //This timer pops for a disconnected session
//so there is no need to report an error back to
//the client
QueueWinStationReset( LogonId ); }
|