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.

722 lines
16 KiB

  1. /*++
  2. Copyright (c) 1999-2001 Microsoft Corporation
  3. Module Name:
  4. redraw.cpp
  5. Abstract:
  6. This file implements redraw handler class.
  7. Author:
  8. Brian Guarraci (briangu) 2001.
  9. Revision History:
  10. --*/
  11. #include <nt.h>
  12. #include <ntrtl.h>
  13. #include <nturtl.h>
  14. #include <windows.h>
  15. #include <process.h>
  16. #include "cmnhdr.h"
  17. #include "redraw.h"
  18. #include "nullio.h"
  19. #include "utils.h"
  20. CRedrawHandler::CRedrawHandler(
  21. IN CLockableIoHandler *IoHandler
  22. )
  23. /*++
  24. Routine Description:
  25. Constructor
  26. Arguments:
  27. IoHanlder - the IoHanlder the redraw handler handles events for
  28. Return Value:
  29. N/A
  30. --*/
  31. {
  32. ASSERT(IoHandler != NULL);
  33. //
  34. // Default: writing is not enabled
  35. //
  36. m_WriteEnabled = FALSE;
  37. //
  38. // Assign our IoHandler
  39. //
  40. m_IoHandler = IoHandler;
  41. //
  42. //
  43. //
  44. m_ThreadExitEvent = NULL;
  45. m_RedrawEventThreadHandle = INVALID_HANDLE_VALUE;
  46. m_RedrawEvent = INVALID_HANDLE_VALUE;
  47. //
  48. // Initialize the critical secion we use for the mirror string
  49. //
  50. InitializeCriticalSection(&m_CriticalSection);
  51. //
  52. // Allocate and initialize the mirror string
  53. //
  54. m_MirrorStringIndex = 0;
  55. m_MirrorString = new WCHAR[MAX_MIRROR_STRING_LENGTH+1];
  56. RtlZeroMemory(m_MirrorString, (MAX_MIRROR_STRING_LENGTH+1) * sizeof(WCHAR));
  57. }
  58. CRedrawHandler::~CRedrawHandler()
  59. /*++
  60. Routine Description:
  61. Desctructor
  62. Arguments:
  63. N/A
  64. Return Value:
  65. N/A
  66. --*/
  67. {
  68. //
  69. // If the TimeOut thread is running, then stop it
  70. //
  71. if ((m_RedrawEventThreadHandle != INVALID_HANDLE_VALUE) &&
  72. ((m_ThreadExitEvent != NULL))) {
  73. //
  74. // Tell the TimeOut Thread to exit
  75. //
  76. SetEvent(m_ThreadExitEvent);
  77. //
  78. // Wait for the threads to exit
  79. //
  80. WaitForSingleObject(
  81. m_RedrawEventThreadHandle,
  82. INFINITE
  83. );
  84. }
  85. //
  86. // if we have the exit event,
  87. // then release it
  88. //
  89. if (m_ThreadExitEvent != NULL) {
  90. CloseHandle(m_ThreadExitEvent);
  91. }
  92. //
  93. // if we have the redraw thread event,
  94. // then release it
  95. //
  96. if (m_RedrawEventThreadHandle != INVALID_HANDLE_VALUE) {
  97. CloseHandle(m_RedrawEventThreadHandle);
  98. }
  99. //
  100. // Note: we need to release attributes that the thread
  101. // uses after we terminate the thread, otherwise
  102. // the thread may attempt to access these attributes
  103. // before it exits.
  104. //
  105. //
  106. // release the critical section
  107. //
  108. DeleteCriticalSection(&m_CriticalSection);
  109. //
  110. // release the mirror string
  111. //
  112. delete [] m_MirrorString;
  113. }
  114. CRedrawHandler*
  115. CRedrawHandler::Construct(
  116. IN CLockableIoHandler *IoHandler,
  117. IN HANDLE RedrawEvent
  118. )
  119. /*++
  120. Routine Description:
  121. This routine constructs a security IoHandler connected
  122. to a channel with the specified attributes.
  123. Arguments:
  124. IoHandler - the IoHandler to write to
  125. Attributes - the attributes of the new channel
  126. Return Value:
  127. Success - A ptr to a CRedrawHandler object.
  128. Failure - NULL
  129. --*/
  130. {
  131. BOOL bStatus;
  132. CRedrawHandler *RedrawHandler;
  133. //
  134. // default
  135. //
  136. bStatus = FALSE;
  137. RedrawHandler = NULL;
  138. do {
  139. ASSERT(IoHandler);
  140. if (!IoHandler) {
  141. break;
  142. }
  143. ASSERT(RedrawEvent != NULL);
  144. if (RedrawEvent == NULL) {
  145. break;
  146. }
  147. ASSERT(RedrawEvent != INVALID_HANDLE_VALUE);
  148. if (RedrawEvent == INVALID_HANDLE_VALUE) {
  149. break;
  150. }
  151. //
  152. // Create a new RedrawHandler
  153. //
  154. RedrawHandler = new CRedrawHandler(IoHandler);
  155. //
  156. // Keep the RedrawEvent so we know when to redraw the
  157. // authentication screen
  158. //
  159. RedrawHandler->m_RedrawEvent = RedrawEvent;
  160. //
  161. // Create the event used to signal the threads to exit
  162. //
  163. RedrawHandler->m_ThreadExitEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
  164. ASSERT(RedrawHandler->m_ThreadExitEvent != NULL);
  165. if (RedrawHandler->m_ThreadExitEvent == NULL) {
  166. break;
  167. }
  168. //
  169. // Create thread to handle redraw events
  170. //
  171. RedrawHandler->m_RedrawEventThreadHandle = (HANDLE)_beginthreadex(
  172. NULL,
  173. 0,
  174. CRedrawHandler::RedrawEventThread,
  175. RedrawHandler,
  176. 0,
  177. (unsigned int*)&RedrawHandler->m_RedrawEventThreadTID
  178. );
  179. if (RedrawHandler->m_RedrawEventThreadHandle == INVALID_HANDLE_VALUE) {
  180. break;
  181. }
  182. //
  183. // we were successful
  184. //
  185. bStatus = TRUE;
  186. } while ( FALSE );
  187. //
  188. // cleanup if necessary
  189. //
  190. if (! bStatus) {
  191. if (RedrawHandler) {
  192. //
  193. // we cant create the handler
  194. //
  195. delete RedrawHandler;
  196. //
  197. // send back a null
  198. //
  199. RedrawHandler = NULL;
  200. }
  201. //
  202. // if the thread event was created,
  203. // then close it
  204. //
  205. if (RedrawHandler->m_ThreadExitEvent != NULL) {
  206. CloseHandle(RedrawHandler->m_ThreadExitEvent);
  207. }
  208. }
  209. return RedrawHandler;
  210. }
  211. BOOL
  212. CRedrawHandler::Write(
  213. PBYTE Buffer,
  214. ULONG BufferSize
  215. )
  216. /*++
  217. Routine Description:
  218. This routine is a shim for the IoHandler write routine.
  219. It writes the string to both the channel
  220. and to the end of the mirror string.
  221. Arguments:
  222. Buffer - the string to write
  223. BufferSize - the string size in bytes
  224. Return Value:
  225. TRUE - no errors
  226. FALSE - otherwise
  227. --*/
  228. {
  229. BOOL bSuccess;
  230. ULONG Length;
  231. //
  232. // default: we succeeded
  233. //
  234. bSuccess = TRUE;
  235. __try {
  236. //
  237. // syncronize access to the mirror string
  238. //
  239. EnterCriticalSection(&m_CriticalSection);
  240. //
  241. // Append the buffer to our internal mirror
  242. // of what we have sent
  243. //
  244. // Note: the incoming buffer points to a WCHAR array,
  245. // hence, we divide by sizeof(WCHAR) to compute
  246. // the # of WCHARs
  247. //
  248. Length = BufferSize / sizeof(WCHAR);
  249. //
  250. // Do boundary checking
  251. //
  252. ASSERT(m_MirrorStringIndex + Length <= MAX_MIRROR_STRING_LENGTH);
  253. if (m_MirrorStringIndex + Length > MAX_MIRROR_STRING_LENGTH) {
  254. bSuccess = FALSE;
  255. __leave;
  256. }
  257. //
  258. // Copy the string into our mirror buffer
  259. //
  260. wcsncpy(
  261. &m_MirrorString[m_MirrorStringIndex],
  262. (PWSTR)Buffer,
  263. Length
  264. );
  265. //
  266. // Adjust our index into the mirror string
  267. //
  268. m_MirrorStringIndex += Length;
  269. //
  270. // Write the message if we can
  271. //
  272. if (m_WriteEnabled) {
  273. bSuccess = m_IoHandler->GetUnlockedIoHandler()->Write(
  274. Buffer,
  275. BufferSize
  276. );
  277. m_IoHandler->GetUnlockedIoHandler()->Flush();
  278. }
  279. }
  280. __finally
  281. {
  282. LeaveCriticalSection(&m_CriticalSection);
  283. }
  284. return bSuccess;
  285. }
  286. BOOL
  287. CRedrawHandler::Flush(
  288. VOID
  289. )
  290. /*++
  291. Routine Description:
  292. Arguments:
  293. Return Value:
  294. --*/
  295. {
  296. //
  297. // Pass through to the IoHandler
  298. //
  299. return m_IoHandler->GetUnlockedIoHandler()->Flush();
  300. }
  301. VOID
  302. CRedrawHandler::Reset(
  303. VOID
  304. )
  305. /*++
  306. Routine Description:
  307. This routine "clears the screen"
  308. Arguments:
  309. None
  310. Return Value:
  311. None
  312. --*/
  313. {
  314. __try {
  315. //
  316. // syncronize access to the mirror string
  317. //
  318. EnterCriticalSection(&m_CriticalSection);
  319. //
  320. // reset the mirror string attributes
  321. //
  322. m_MirrorStringIndex = 0;
  323. m_MirrorString[m_MirrorStringIndex] = UNICODE_NULL;
  324. }
  325. __finally
  326. {
  327. LeaveCriticalSection(&m_CriticalSection);
  328. }
  329. }
  330. BOOL
  331. CRedrawHandler::WriteMirrorString(
  332. VOID
  333. )
  334. /*++
  335. Routine Description:
  336. This routine writes the entire current Mirror string to the channel.
  337. Arguments:
  338. None
  339. Return Value:
  340. TRUE - no errors
  341. FALSE - otherwise
  342. --*/
  343. {
  344. BOOL bSuccess;
  345. //
  346. // Default: we succeeded
  347. //
  348. bSuccess = TRUE;
  349. //
  350. // Only write if our IoHandler is locked.
  351. //
  352. // If they are unlocked, they will handle
  353. // the redraw events. If they are locked,
  354. // we need to handle them.
  355. //
  356. if (m_IoHandler->IsLocked() && m_WriteEnabled) {
  357. __try {
  358. //
  359. // syncronize access to the mirror string
  360. //
  361. EnterCriticalSection(&m_CriticalSection);
  362. //
  363. // Write the message
  364. //
  365. bSuccess = m_IoHandler->GetUnlockedIoHandler()->Write(
  366. (PBYTE)m_MirrorString,
  367. m_MirrorStringIndex * sizeof(WCHAR)
  368. );
  369. m_IoHandler->GetUnlockedIoHandler()->Flush();
  370. }
  371. __finally
  372. {
  373. LeaveCriticalSection(&m_CriticalSection);
  374. }
  375. }
  376. return bSuccess;
  377. }
  378. unsigned int
  379. CRedrawHandler::RedrawEventThread(
  380. PVOID pParam
  381. )
  382. /*++
  383. Routine Description:
  384. This routine handles the redraw event from the SAC driver.
  385. It does this by being a combination event handler and screen
  386. scraper. When the event fires, we immediately attempt to
  387. draw the latest screen and then it goes into screen scraping
  388. mode. This duality ensures that if we service the event
  389. before we actually write anything to the mirror string,
  390. that we push the string to the user correctly.
  391. Arguments:
  392. pParam - thread context
  393. Return Value:
  394. thread return value
  395. --*/
  396. {
  397. BOOL bContinueSession;
  398. DWORD dwRetVal;
  399. CRedrawHandler *IoHandler;
  400. HANDLE handles[2];
  401. WCHAR LastSeen[MAX_MIRROR_STRING_LENGTH+1];
  402. enum {
  403. THREAD_EXIT = WAIT_OBJECT_0,
  404. CHANNEL_REDRAW_EVENT
  405. };
  406. //
  407. // default: listen
  408. //
  409. bContinueSession = TRUE;
  410. //
  411. // Get the session object
  412. //
  413. IoHandler = (CRedrawHandler*)pParam;
  414. //
  415. // Default: it is not an appropriate time to scrape
  416. //
  417. InterlockedExchange(&IoHandler->m_WriteEnabled, FALSE);
  418. //
  419. // Assign the events to listen for
  420. //
  421. handles[0] = IoHandler->m_ThreadExitEvent;
  422. handles[1] = IoHandler->m_RedrawEvent;
  423. //
  424. // While we should listen:
  425. //
  426. // 1. wait for a HasNewDataEvent from the SAC driver
  427. // 2. wait for a CloseEvent from the SAC driver
  428. //
  429. while ( bContinueSession ) {
  430. ULONG HandleCount;
  431. //
  432. // If scraping is enabled,
  433. // then don't wait on the scrape event.
  434. //
  435. // Note: the redraw event must be the last event
  436. // in the handles array
  437. //
  438. HandleCount = IoHandler->m_WriteEnabled ? 1 : 2;
  439. //
  440. // Wait for our events
  441. //
  442. dwRetVal = WaitForMultipleObjects(
  443. HandleCount,
  444. handles,
  445. FALSE,
  446. 100 // 100ms
  447. );
  448. switch ( dwRetVal ) {
  449. case CHANNEL_REDRAW_EVENT: {
  450. //
  451. // We need to scrape the mirror string to ensure we
  452. // got all of the mirror string to the user
  453. //
  454. InterlockedExchange(&IoHandler->m_WriteEnabled, TRUE);
  455. //
  456. // attempt to redraw the authentication screen
  457. //
  458. bContinueSession = IoHandler->WriteMirrorString();
  459. break;
  460. case WAIT_TIMEOUT:
  461. if (IoHandler->m_WriteEnabled) {
  462. //
  463. // Here we do a simplified screen scraping using the Mirror
  464. // string as our "screen." The purpose of this scraping
  465. // is to ensure that the user gets the latest authentication
  466. // screen. If we don't do this, it is possible for the Mirror
  467. // string to be updated after we catch the Redraw event,
  468. // which results in us not sending the entire Mirror string.
  469. //
  470. __try {
  471. BOOL bDifferent;
  472. //
  473. // syncronize access to the mirror string
  474. //
  475. EnterCriticalSection(&IoHandler->m_CriticalSection);
  476. //
  477. // See if our last seen string == the current mirror string
  478. //
  479. bDifferent = (wcscmp(LastSeen, IoHandler->m_MirrorString) == 0);
  480. //
  481. // If there is a difference,
  482. // then we need to update the screen
  483. //
  484. if (bDifferent) {
  485. //
  486. // attempt to redraw the authentication screen
  487. //
  488. bContinueSession = IoHandler->WriteMirrorString();
  489. //
  490. // make the current mirror string, our last
  491. //
  492. ASSERT(wcslen(IoHandler->m_MirrorString) <= MAX_MIRROR_STRING_LENGTH);
  493. wcscpy(LastSeen, IoHandler->m_MirrorString);
  494. }
  495. }
  496. __finally
  497. {
  498. LeaveCriticalSection(&IoHandler->m_CriticalSection);
  499. }
  500. //
  501. // Wait until the event clears by looking
  502. // for a WAIT_TIMEOUT
  503. //
  504. dwRetVal = WaitForSingleObject(
  505. IoHandler->m_RedrawEvent,
  506. 0
  507. );
  508. //
  509. // Check the wait result
  510. //
  511. switch (dwRetVal) {
  512. case WAIT_TIMEOUT:
  513. //
  514. // We need to stop scraping now
  515. //
  516. InterlockedExchange(&IoHandler->m_WriteEnabled, FALSE);
  517. break;
  518. default:
  519. ASSERT (dwRetVal != WAIT_FAILED);
  520. if (dwRetVal == WAIT_FAILED) {
  521. bContinueSession = false;
  522. }
  523. break;
  524. }
  525. }
  526. break;
  527. }
  528. default:
  529. //
  530. // incase WAIT_FAILED, call GetLastError()
  531. //
  532. ASSERT(dwRetVal != WAIT_FAILED);
  533. //
  534. // An error has occured, stop listening
  535. //
  536. bContinueSession = FALSE;
  537. break;
  538. }
  539. }
  540. return 0;
  541. }