Leaked source code of windows server 2003
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.

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