Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

434 lines
12 KiB

  1. /*************************************************************************
  2. *
  3. * wininit.c
  4. *
  5. * Window station init and destroy routines
  6. *
  7. * Copyright Microsoft Corporation, 1998
  8. *
  9. *
  10. *************************************************************************/
  11. /*
  12. * Includes
  13. */
  14. #include "precomp.h"
  15. #pragma hdrstop
  16. /*
  17. * Local data
  18. */
  19. #define LOGOFF_TIMER 120000L
  20. #define MODULE_SIZE 1024 /* Default size for retrive of module data */
  21. #define VDDATA_LENGTH 1024
  22. /*
  23. * Internal Procedures
  24. */
  25. VOID StartLogonTimers( PWINSTATION );
  26. VOID IdleTimeout( ULONG );
  27. VOID LogonTimeout( ULONG );
  28. VOID IdleLogoffTimeout( ULONG );
  29. VOID LogoffTimeout( ULONG );
  30. /*******************************************************************************
  31. *
  32. * StartLogonTimers
  33. *
  34. * This routine is called when an user is logged on.
  35. * Timers are started for idle input and total logon time.
  36. *
  37. * ENTRY:
  38. * None.
  39. *
  40. * EXIT:
  41. * None.
  42. *
  43. ******************************************************************************/
  44. VOID
  45. StartLogonTimers( PWINSTATION pWinStation )
  46. {
  47. int Status;
  48. ULONG Timer;
  49. // for Session0 and any console sessions, timeouts don't make sense
  50. if ( ( pWinStation->LogonId != 0 ) && ( pWinStation->LogonId != USER_SHARED_DATA->ActiveConsoleId ) ) {
  51. if ( Timer = pWinStation->Config.Config.User.MaxIdleTime ) {
  52. if ( !pWinStation->fIdleTimer ) {
  53. Status = IcaTimerCreate( 0, &pWinStation->hIdleTimer );
  54. if ( NT_SUCCESS( Status ) )
  55. pWinStation->fIdleTimer = TRUE;
  56. else
  57. DBGPRINT(( "StartLogonTimers - failed to create idle timer \n" ));
  58. }
  59. if ( pWinStation->fIdleTimer )
  60. IcaTimerStart( pWinStation->hIdleTimer, IdleTimeout,
  61. LongToPtr( pWinStation->LogonId ), Timer );
  62. }
  63. if ( Timer = pWinStation->Config.Config.User.MaxConnectionTime ) {
  64. if ( !pWinStation->fLogonTimer ) {
  65. Status = IcaTimerCreate( 0, &pWinStation->hLogonTimer );
  66. if ( NT_SUCCESS( Status ) )
  67. pWinStation->fLogonTimer = TRUE;
  68. else
  69. DBGPRINT(( "StartLogonTimers - failed to create logon timer \n" ));
  70. }
  71. if ( pWinStation->fLogonTimer )
  72. IcaTimerStart( pWinStation->hLogonTimer, LogonTimeout,
  73. LongToPtr( pWinStation->LogonId ), Timer );
  74. }
  75. }
  76. }
  77. /*******************************************************************************
  78. *
  79. * IdleTimeout
  80. *
  81. * This routine is called when the idle timer expires.
  82. * Send the user a warning message and start timer to logoff in 2 minutes.
  83. *
  84. * ENTRY:
  85. * LogonId
  86. *
  87. * EXIT:
  88. * None.
  89. *
  90. ******************************************************************************/
  91. VOID IdleTimeout( ULONG LogonId )
  92. {
  93. LARGE_INTEGER liT;
  94. ULONG ulTimeDelta;
  95. ICA_STACK_LAST_INPUT_TIME Ica_Stack_Last_Input_Time;
  96. NTSTATUS Status;
  97. ULONG cbReturned;
  98. PWINSTATION pWinStation;
  99. WINSTATION_APIMSG msg;
  100. pWinStation = FindWinStationById( LogonId, FALSE );
  101. if ( !pWinStation )
  102. return;
  103. if ( !pWinStation->hStack )
  104. goto done;
  105. if ( !pWinStation->fIdleTimer )
  106. goto done;
  107. // Check for availability
  108. if ( pWinStation->pWsx &&
  109. pWinStation->pWsx->pWsxIcaStackIoControl ) {
  110. Status = pWinStation->pWsx->pWsxIcaStackIoControl(
  111. pWinStation->pWsxContext,
  112. pWinStation->hIca,
  113. pWinStation->hStack,
  114. IOCTL_ICA_STACK_QUERY_LAST_INPUT_TIME,
  115. NULL,
  116. 0,
  117. &Ica_Stack_Last_Input_Time,
  118. sizeof( Ica_Stack_Last_Input_Time ),
  119. &cbReturned );
  120. }
  121. else {
  122. Status = STATUS_INVALID_PARAMETER;
  123. }
  124. if ( !NT_SUCCESS( Status ) ) {
  125. goto done;
  126. }
  127. /*
  128. * Check if there was input during the idle time
  129. */
  130. NtQuerySystemTime( &liT );
  131. // calculate delta in time & convert from 100ns unit to milliseconds
  132. liT = RtlExtendedLargeIntegerDivide(
  133. RtlLargeIntegerSubtract( liT, Ica_Stack_Last_Input_Time.LastInputTime ),
  134. 10000, NULL );
  135. ulTimeDelta = (ULONG)liT.LowTime;
  136. TRACE((hTrace,TC_ICASRV,TT_API1, "IdleTimeout: delta = %d, max idle = %d\n", ulTimeDelta,
  137. pWinStation->Config.Config.User.MaxIdleTime ));
  138. if ( ulTimeDelta < pWinStation->Config.Config.User.MaxIdleTime ) {
  139. IcaTimerStart( pWinStation->hIdleTimer, IdleTimeout, LongToPtr( LogonId ),
  140. pWinStation->Config.Config.User.MaxIdleTime - ulTimeDelta );
  141. } else {
  142. TCHAR szTitle[128];
  143. TCHAR szMsg[256];
  144. int cchTitle, cchMessage;
  145. IcaTimerStart( pWinStation->hIdleTimer, IdleLogoffTimeout,
  146. LongToPtr( LogonId ), LOGOFF_TIMER );
  147. if ( !(cchTitle = LoadString(hModuleWin, STR_CITRIX_IDLE_TITLE, szTitle, sizeof(szTitle)/sizeof(TCHAR))) )
  148. goto done;
  149. if ( pWinStation->Config.Config.User.fResetBroken )
  150. {
  151. if ( !(cchMessage = LoadString(hModuleWin, STR_CITRIX_IDLE_MSG_LOGOFF, szMsg, sizeof(szMsg)/sizeof(TCHAR)) ))
  152. goto done;
  153. }
  154. else
  155. {
  156. if ( !(cchMessage = LoadString(hModuleWin, STR_CITRIX_IDLE_MSG_DISCON, szMsg, sizeof(szMsg)/sizeof(TCHAR)) ))
  157. goto done;
  158. }
  159. msg.u.SendMessage.pTitle = szTitle;
  160. msg.u.SendMessage.TitleLength = (cchTitle+1) * sizeof(TCHAR);
  161. msg.u.SendMessage.pMessage = szMsg;
  162. msg.u.SendMessage.MessageLength = (cchMessage+1) * sizeof(TCHAR);
  163. msg.u.SendMessage.Style = MB_OK | MB_ICONSTOP;
  164. msg.u.SendMessage.Timeout = (ULONG)LOGOFF_TIMER/1000;
  165. msg.u.SendMessage.Response = 0;
  166. msg.u.SendMessage.DoNotWait = TRUE;
  167. msg.ApiNumber = SMWinStationDoMessage;
  168. Status = SendWinStationCommand( pWinStation, &msg, 0 );
  169. }
  170. done:
  171. ReleaseWinStation( pWinStation );
  172. }
  173. /*******************************************************************************
  174. *
  175. * LogonTimeout
  176. *
  177. * This routine is called when the logon timer expires.
  178. * Send the user a warning message and start timer to logoff in 2 minutes.
  179. *
  180. * ENTRY:
  181. * LogonId
  182. *
  183. * EXIT:
  184. * None.
  185. *
  186. ******************************************************************************/
  187. VOID LogonTimeout( ULONG LogonId )
  188. {
  189. TCHAR szTitle[128];
  190. TCHAR szMsg[256];
  191. PWINSTATION pWinStation;
  192. NTSTATUS Status;
  193. WINSTATION_APIMSG msg;
  194. int cchTitle, cchMsg;
  195. pWinStation = FindWinStationById( LogonId, FALSE );
  196. if ( !pWinStation )
  197. return;
  198. if ( !pWinStation->fLogonTimer)
  199. goto done;
  200. if ( !(cchTitle = LoadString(hModuleWin, STR_CITRIX_LOGON_TITLE, szTitle, sizeof(szTitle)/sizeof(TCHAR)) ))
  201. goto done;
  202. if ( pWinStation->Config.Config.User.fResetBroken )
  203. {
  204. if ( !(cchMsg = LoadString(hModuleWin, STR_CITRIX_LOGON_MSG_LOGOFF, szMsg, sizeof(szMsg)/sizeof(TCHAR)) ))
  205. goto done;
  206. }
  207. else
  208. {
  209. if ( !(cchMsg = LoadString(hModuleWin, STR_CITRIX_LOGON_MSG_DISCON, szMsg, sizeof(szMsg)/sizeof(TCHAR)) ))
  210. goto done;
  211. }
  212. msg.u.SendMessage.pTitle = szTitle;
  213. msg.u.SendMessage.TitleLength = ( cchTitle+1 ) * sizeof(TCHAR);
  214. msg.u.SendMessage.pMessage = szMsg;
  215. msg.u.SendMessage.MessageLength = ( cchMsg+1 ) * sizeof(TCHAR);
  216. msg.u.SendMessage.Style = MB_OK | MB_ICONSTOP;
  217. msg.u.SendMessage.Timeout = (ULONG)LOGOFF_TIMER/1000;
  218. msg.u.SendMessage.Response = 0;
  219. msg.u.SendMessage.DoNotWait = TRUE;
  220. msg.ApiNumber = SMWinStationDoMessage;
  221. Status = SendWinStationCommand( pWinStation, &msg, 0 );
  222. IcaTimerStart( pWinStation->hLogonTimer, LogoffTimeout,
  223. LongToPtr( LogonId ), LOGOFF_TIMER );
  224. if (pWinStation->fIdleTimer) {
  225. pWinStation->fIdleTimer = FALSE;
  226. IcaTimerClose( pWinStation->hIdleTimer );
  227. }
  228. done:
  229. ReleaseWinStation( pWinStation );
  230. }
  231. /*******************************************************************************
  232. *
  233. * IdleLogoffTimeout
  234. *
  235. * This routine is called when the logoff timer expires.
  236. * Check for input before logging user off
  237. *
  238. * ENTRY:
  239. * LogonId
  240. *
  241. * EXIT:
  242. * None.
  243. *
  244. ******************************************************************************/
  245. VOID IdleLogoffTimeout( ULONG LogonId )
  246. {
  247. LARGE_INTEGER liT;
  248. ULONG ulTimeDelta;
  249. ICA_STACK_LAST_INPUT_TIME Ica_Stack_Last_Input_Time;
  250. NTSTATUS Status;
  251. ULONG cbReturned;
  252. PWINSTATION pWinStation;
  253. pWinStation = FindWinStationById( LogonId, FALSE );
  254. if ( !pWinStation )
  255. return;
  256. if ( !pWinStation->hStack )
  257. goto done;
  258. if ( !pWinStation->fIdleTimer )
  259. goto done;
  260. // Check for availability
  261. if ( pWinStation->pWsx &&
  262. pWinStation->pWsx->pWsxIcaStackIoControl ) {
  263. Status = pWinStation->pWsx->pWsxIcaStackIoControl(
  264. pWinStation->pWsxContext,
  265. pWinStation->hIca,
  266. pWinStation->hStack,
  267. IOCTL_ICA_STACK_QUERY_LAST_INPUT_TIME,
  268. NULL,
  269. 0,
  270. &Ica_Stack_Last_Input_Time,
  271. sizeof( Ica_Stack_Last_Input_Time ),
  272. &cbReturned );
  273. }
  274. else {
  275. Status = STATUS_INVALID_PARAMETER;
  276. }
  277. if ( !NT_SUCCESS( Status ) ) {
  278. goto done;
  279. }
  280. NtQuerySystemTime( &liT );
  281. liT = RtlExtendedLargeIntegerDivide(
  282. RtlLargeIntegerSubtract( liT, Ica_Stack_Last_Input_Time.LastInputTime ),
  283. 10000, NULL );
  284. ulTimeDelta = (ULONG)liT.LowTime;
  285. TRACE((hTrace,TC_ICASRV,TT_API1, "IdleTimeout: delta = %d, max idle = %d\n", ulTimeDelta,
  286. LOGOFF_TIMER ));
  287. if ( ulTimeDelta < LOGOFF_TIMER ) {
  288. IcaTimerStart( pWinStation->hIdleTimer, IdleTimeout, LongToPtr( LogonId ),
  289. pWinStation->Config.Config.User.MaxIdleTime - ulTimeDelta );
  290. } else
  291. LogoffTimeout( LogonId );
  292. done:
  293. ReleaseWinStation( pWinStation );
  294. }
  295. /*******************************************************************************
  296. *
  297. * LogoffTimeout
  298. *
  299. * This routine is called when the logoff timer expires.
  300. * Log user off and disconnect the winstation.
  301. *
  302. * ENTRY:
  303. * LogonId - LogonId to logout
  304. *
  305. * EXIT:
  306. * None.
  307. *
  308. ******************************************************************************/
  309. VOID LogoffTimeout(ULONG LogonId)
  310. {
  311. PWINSTATION pWinStation;
  312. pWinStation = FindWinStationById( LogonId, FALSE );
  313. if ( !pWinStation )
  314. return;
  315. //
  316. // Report disconnect reason back to client
  317. //
  318. if(pWinStation->WinStationName[0] &&
  319. pWinStation->pWsx &&
  320. pWinStation->pWsx->pWsxSetErrorInfo &&
  321. pWinStation->pWsxContext)
  322. {
  323. ULONG discReason = 0;
  324. if(pWinStation->fIdleTimer)
  325. {
  326. discReason = TS_ERRINFO_IDLE_TIMEOUT;
  327. }
  328. else if(pWinStation->fLogonTimer)
  329. {
  330. discReason = TS_ERRINFO_LOGON_TIMEOUT;
  331. }
  332. if(discReason)
  333. {
  334. pWinStation->pWsx->pWsxSetErrorInfo(
  335. pWinStation->pWsxContext,
  336. discReason,
  337. FALSE); //stack lock not held
  338. }
  339. }
  340. if ( pWinStation->Config.Config.User.fResetBroken ) {
  341. ReleaseWinStation( pWinStation );
  342. QueueWinStationReset( LogonId );
  343. }
  344. else {
  345. ReleaseWinStation( pWinStation );
  346. QueueWinStationDisconnect( LogonId );
  347. }
  348. }
  349. /*******************************************************************************
  350. *
  351. * DisconnectTimeout
  352. *
  353. * This routine is called when the disconnect timer expires.
  354. * Reset the winstation.
  355. *
  356. * ENTRY:
  357. * LogonId
  358. *
  359. * EXIT:
  360. * None.
  361. *
  362. ******************************************************************************/
  363. VOID DisconnectTimeout( ULONG LogonId )
  364. {
  365. //This timer pops for a disconnected session
  366. //so there is no need to report an error back to
  367. //the client
  368. QueueWinStationReset( LogonId );
  369. }