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.

861 lines
18 KiB

  1. /*++
  2. Copyright (c) 1999-2001 Microsoft Corporation
  3. Module Name:
  4. session.cpp
  5. Abstract:
  6. Class for creating a command console shell
  7. Author:
  8. Brian Guarraci (briangu) 2001.
  9. Revision History:
  10. --*/
  11. #include <Session.h>
  12. #include <assert.h>
  13. #include <process.h>
  14. #include "secio.h"
  15. #include "utils.h"
  16. #include "scraper.h"
  17. #include "vtutf8scraper.h"
  18. extern "C" {
  19. #include <ntddsac.h>
  20. #include <sacapi.h>
  21. }
  22. CSession::CSession()
  23. /*++
  24. Routine Description:
  25. Constructor
  26. Arguments:
  27. None
  28. Return Value:
  29. N/A
  30. --*/
  31. {
  32. //
  33. //
  34. //
  35. m_dwPollInterval = MIN_POLL_INTERVAL;
  36. //
  37. // Initialize the # of rows and cols the session
  38. // screen will have
  39. //
  40. m_wCols = DEFAULT_COLS;
  41. m_wRows = DEFAULT_ROWS;
  42. //
  43. // Initialize the username and password for
  44. // the authentication of a user
  45. //
  46. RtlZeroMemory(m_UserName, sizeof(m_UserName));
  47. RtlZeroMemory(m_DomainName, sizeof(m_DomainName));
  48. //
  49. // Initialize the WaitForIo attributes
  50. //
  51. m_bContinueSession = true;
  52. m_dwHandleCount = 0;
  53. //
  54. // NULL all event the handles we use
  55. //
  56. m_ThreadExitEvent = NULL;
  57. m_SacChannelCloseEvent = NULL;
  58. m_SacChannelHasNewDataEvent = NULL;
  59. m_SacChannelLockEvent = NULL;
  60. m_SacChannelRedrawEvent = NULL;
  61. //
  62. // thread handle is invalid
  63. //
  64. m_InputThreadHandle = INVALID_HANDLE_VALUE;
  65. //
  66. //
  67. //
  68. m_ioHandler = NULL;
  69. m_Scraper = NULL;
  70. m_Shell = NULL;
  71. }
  72. CSession::~CSession()
  73. /*++
  74. Routine Description:
  75. Destructor
  76. Arguments:
  77. N/A
  78. Return Value:
  79. N/A
  80. --*/
  81. {
  82. if (m_Shell) {
  83. delete m_Shell;
  84. }
  85. if (m_Scraper) {
  86. delete m_Scraper;
  87. }
  88. if (m_ioHandler) {
  89. delete m_ioHandler;
  90. }
  91. if (m_ThreadExitEvent) {
  92. CloseHandle( m_ThreadExitEvent );
  93. }
  94. if (m_SacChannelCloseEvent) {
  95. CloseHandle( m_SacChannelCloseEvent );
  96. }
  97. if (m_SacChannelHasNewDataEvent) {
  98. CloseHandle( m_SacChannelHasNewDataEvent );
  99. }
  100. if (m_SacChannelLockEvent) {
  101. CloseHandle( m_SacChannelLockEvent );
  102. }
  103. if (m_SacChannelRedrawEvent) {
  104. CloseHandle( m_SacChannelRedrawEvent );
  105. }
  106. }
  107. BOOL
  108. CSession::Authenticate(
  109. OUT PHANDLE phToken
  110. )
  111. /*++
  112. Routine Description:
  113. This routine attempts to authenticate a user (if necessary) and
  114. acquire credentials.
  115. Arguments:
  116. hToken - on success, contains the authenticated credentials
  117. Return Value:
  118. TRUE - success
  119. FALSE - otherwise
  120. Security:
  121. interface:
  122. registry
  123. external input
  124. LogonUser()
  125. --*/
  126. {
  127. BOOL bSuccess;
  128. PWCHAR Password;
  129. //
  130. // Allocate the password on the heap
  131. //
  132. Password = new WCHAR[MAX_PASSWORD_LENGTH+1];
  133. //
  134. // Purge the password buffer
  135. //
  136. RtlZeroMemory(Password, (MAX_PASSWORD_LENGTH+1) * sizeof(Password[0]));
  137. //
  138. // Default: the credentials are invalid
  139. //
  140. *phToken = INVALID_HANDLE_VALUE;
  141. //
  142. // Default: we were successful
  143. //
  144. bSuccess = TRUE;
  145. //
  146. // Attempt to authenticate a user if authentication
  147. // as actually needed.
  148. //
  149. do {
  150. if( NeedCredentials() ) {
  151. //
  152. // Get the credentials to authenticate
  153. //
  154. bSuccess = m_ioHandler->RetrieveCredentials(
  155. m_UserName,
  156. sizeof(m_UserName) / sizeof(m_UserName[0]),
  157. m_DomainName,
  158. sizeof(m_DomainName) / sizeof(m_DomainName[0]),
  159. Password,
  160. MAX_PASSWORD_LENGTH+1
  161. );
  162. if (!bSuccess) {
  163. break;
  164. }
  165. //
  166. // Attempt the actual authentication
  167. //
  168. bSuccess = m_ioHandler->AuthenticateCredentials(
  169. m_UserName,
  170. m_DomainName,
  171. Password,
  172. phToken
  173. );
  174. if (!bSuccess) {
  175. break;
  176. }
  177. }
  178. } while ( FALSE );
  179. //
  180. // Purge and release the password buffer
  181. //
  182. RtlSecureZeroMemory(Password, (MAX_PASSWORD_LENGTH+1) * sizeof(Password[0]));
  183. delete [] Password;
  184. return bSuccess;
  185. }
  186. BOOL
  187. CSession::Lock(
  188. VOID
  189. )
  190. /*++
  191. Routine Description:
  192. This routine manages the locking of the session.
  193. Arguments:
  194. None
  195. Return Value:
  196. status
  197. --*/
  198. {
  199. //
  200. // Lock the IOHandler
  201. //
  202. // this causes the Security Iohandler to switch from using
  203. // the SAC IOHandler to using the NULLIO handler.
  204. //
  205. m_ioHandler->Lock();
  206. return TRUE;
  207. }
  208. BOOL
  209. CSession::Unlock(
  210. VOID
  211. )
  212. /*++
  213. Routine Description:
  214. This routine manages the unlocking of the session after a user
  215. has authenticated.
  216. Arguments:
  217. None
  218. Return Value:
  219. status
  220. --*/
  221. {
  222. BOOL bStatus;
  223. //
  224. // Unlock the IOHandler
  225. //
  226. // this causes the Security Iohandler to switch from using
  227. // the NULLIO handler to using the SAC IOhandler
  228. //
  229. m_ioHandler->Unlock();
  230. //
  231. // It is possible that the Lock Event was signalled while we were
  232. // waiting for authentication
  233. //
  234. // e.g. Imagine a user starting a cmd session,
  235. // not logging in, and walking away for longer than the timeout
  236. // period
  237. //
  238. // -or-
  239. //
  240. // a SAC "lock" command was issued while the session was already
  241. // locked.
  242. //
  243. // After the user logs on successfully, we should not lock again.
  244. // Hence, we need to reset the lock event.
  245. //
  246. // Note: It is not correct to do this in the security IO handler, as it
  247. // should not have global knowledge of all the circumstances that
  248. // can signal the lock event.
  249. //
  250. bStatus = ResetEvent(m_SacChannelLockEvent);
  251. return bStatus;
  252. }
  253. BOOL
  254. CSession::Init(
  255. VOID
  256. )
  257. /*++
  258. Routine Description:
  259. This routine does the core initialization for the session.
  260. If this routine is successful, the WaitForIo routine may be called.
  261. Arguments:
  262. None
  263. Return Value:
  264. TRUE - the session was successfully initialized
  265. FALSE - otherwise
  266. --*/
  267. {
  268. SAC_CHANNEL_OPEN_ATTRIBUTES Attributes;
  269. HANDLE hToken;
  270. BOOL bSuccess;
  271. //
  272. // Initialize the last error status
  273. //
  274. SetLastError( 0 );
  275. //
  276. // Construct the manually resetting events that we'll use
  277. //
  278. // Note: we do not need to CloseHandle() on the events if
  279. // fail because they are cleaned up in the destructor
  280. //
  281. m_SacChannelLockEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
  282. ASSERT_STATUS(m_SacChannelLockEvent, FALSE);
  283. m_SacChannelCloseEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
  284. ASSERT_STATUS(m_SacChannelCloseEvent, FALSE);
  285. m_ThreadExitEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
  286. ASSERT_STATUS(m_ThreadExitEvent, FALSE);
  287. m_SacChannelHasNewDataEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
  288. ASSERT_STATUS(m_SacChannelHasNewDataEvent, FALSE);
  289. m_SacChannelRedrawEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
  290. ASSERT_STATUS(m_SacChannelRedrawEvent, FALSE);
  291. //
  292. // Configure the attributes of the command console channel
  293. //
  294. // Note: we don't use all of the attributes since most are defaulted
  295. // in the SAC driver
  296. //
  297. RtlZeroMemory(&Attributes, sizeof(SAC_CHANNEL_OPEN_ATTRIBUTES));
  298. Attributes.Flags = SAC_CHANNEL_FLAG_CLOSE_EVENT |
  299. SAC_CHANNEL_FLAG_HAS_NEW_DATA_EVENT |
  300. SAC_CHANNEL_FLAG_LOCK_EVENT |
  301. SAC_CHANNEL_FLAG_REDRAW_EVENT;
  302. Attributes.CloseEvent = m_SacChannelCloseEvent;
  303. Attributes.HasNewDataEvent = m_SacChannelHasNewDataEvent;
  304. Attributes.LockEvent = m_SacChannelLockEvent;
  305. Attributes.RedrawEvent = m_SacChannelRedrawEvent;
  306. //
  307. // Attempt to open the Secure Io Handler to the SAC command console channel
  308. //
  309. m_ioHandler = CSecurityIoHandler::Construct(Attributes);
  310. if (! m_ioHandler) {
  311. return FALSE;
  312. }
  313. //
  314. // Attempt to authenticate the session user
  315. //
  316. bSuccess = Authenticate(&hToken);
  317. if (!bSuccess) {
  318. return (FALSE);
  319. }
  320. //
  321. // The user successfully authenticated, so unlock the session
  322. //
  323. Unlock();
  324. //
  325. // Create the scraper we'll use for this session
  326. //
  327. m_Scraper = new CVTUTF8Scraper(
  328. m_ioHandler,
  329. m_wCols,
  330. m_wRows
  331. );
  332. //
  333. // Create the shell we'll use for this session
  334. //
  335. m_Shell = new CShell();
  336. //
  337. // Attempt to launch the command console session
  338. //
  339. bSuccess = m_Shell->StartUserSession (
  340. this,
  341. hToken
  342. );
  343. ASSERT_STATUS(bSuccess, FALSE);
  344. //
  345. // We are done with the token
  346. //
  347. CloseHandle(hToken);
  348. //
  349. // Start the scraper
  350. //
  351. bSuccess = m_Scraper->Start();
  352. ASSERT_STATUS(bSuccess, FALSE);
  353. //
  354. // The scraping thread needs to also listen if the SAC channel closes
  355. //
  356. AddHandleToWaitOn(m_SacChannelCloseEvent);
  357. AddHandleToWaitOn(m_SacChannelLockEvent);
  358. AddHandleToWaitOn(m_SacChannelRedrawEvent);
  359. //
  360. // Create threads to handle Input
  361. //
  362. m_InputThreadHandle = (HANDLE)_beginthreadex(
  363. NULL,
  364. 0,
  365. CSession::InputThread,
  366. this,
  367. 0,
  368. (unsigned int*)&m_InputThreadTID
  369. );
  370. ASSERT_STATUS(m_InputThreadHandle != INVALID_HANDLE_VALUE, FALSE);
  371. //
  372. // We successfully initialized the session
  373. //
  374. return( TRUE );
  375. }
  376. void
  377. CSession::AddHandleToWaitOn( HANDLE hNew )
  378. /*++
  379. Routine Description:
  380. This routine adds a handle to an array of handles
  381. that will be waiting on in "WaitForIo"
  382. Note: the handle array is fixed length, so if there
  383. are additional handles which need to be waited
  384. on, MAX_HANDLES must be modified
  385. Arguments:
  386. hNew - the new handle to wait on
  387. Return Value:
  388. None
  389. --*/
  390. {
  391. ASSERT( m_dwHandleCount < MAX_HANDLES );
  392. ASSERT( hNew );
  393. //
  394. // Add the new handle to our array of multiple handles
  395. //
  396. m_rghHandlestoWaitOn[ m_dwHandleCount ] = hNew;
  397. //
  398. // Account for the new handle
  399. //
  400. m_dwHandleCount++;
  401. }
  402. void
  403. CSession::WaitForIo(
  404. VOID
  405. )
  406. /*++
  407. Routine Description:
  408. This routine is the main work loop for the session and
  409. is responsible for:
  410. running the scraper
  411. handling the session close event
  412. handling the session redraw event
  413. handling the session lock event
  414. Arguments:
  415. None
  416. Return Value:
  417. None
  418. --*/
  419. {
  420. DWORD dwRetVal = WAIT_FAILED;
  421. BOOL ScrapeEnabled;
  422. enum {
  423. CMD_KILLED = WAIT_OBJECT_0,
  424. CHANNEL_CLOSE_EVENT,
  425. CHANNEL_LOCK_EVENT,
  426. CHANNEL_REDRAW_EVENT
  427. };
  428. //
  429. // Default: it is not an appropriate time to scrape
  430. //
  431. ScrapeEnabled = FALSE;
  432. //
  433. // Service the session's events
  434. //
  435. while ( m_bContinueSession ) {
  436. ULONG HandleCount;
  437. //
  438. // If scraping is enabled,
  439. // then don't wait on the scrape event.
  440. //
  441. // Note: the redraw event must be the last event
  442. // in the m_rghHandlestoWaitOn array
  443. //
  444. HandleCount = ScrapeEnabled ? m_dwHandleCount - 1 : m_dwHandleCount;
  445. dwRetVal = WaitForMultipleObjects(
  446. HandleCount,
  447. m_rghHandlestoWaitOn,
  448. FALSE,
  449. m_dwPollInterval
  450. );
  451. switch ( dwRetVal ) {
  452. case CHANNEL_REDRAW_EVENT:
  453. ASSERT(!ScrapeEnabled);
  454. //
  455. // Tell the screen scraper we need a full dump of it's screen
  456. //
  457. m_Scraper->DisplayFullScreen();
  458. //
  459. // We are now an appropriate time to scrape
  460. //
  461. ScrapeEnabled = TRUE;
  462. break;
  463. case WAIT_TIMEOUT:
  464. if (ScrapeEnabled) {
  465. //
  466. // Scrape
  467. //
  468. m_bContinueSession = m_Scraper->Write();
  469. //
  470. // Wait until the event clears by looking
  471. // for a WAIT_TIMEOUT
  472. //
  473. dwRetVal = WaitForSingleObject(
  474. m_SacChannelRedrawEvent,
  475. 0
  476. );
  477. //
  478. // Check the wait result
  479. //
  480. switch (dwRetVal) {
  481. case WAIT_TIMEOUT:
  482. //
  483. // We need to stop scraping now
  484. //
  485. ScrapeEnabled = FALSE;
  486. break;
  487. default:
  488. ASSERT (dwRetVal != WAIT_FAILED);
  489. if (dwRetVal == WAIT_FAILED) {
  490. m_bContinueSession = false;
  491. }
  492. break;
  493. }
  494. }
  495. break;
  496. case CHANNEL_LOCK_EVENT:
  497. BOOL bSuccess;
  498. HANDLE hToken;
  499. //
  500. // Lock the session
  501. //
  502. Lock();
  503. //
  504. // Attempt to authenticate the session user
  505. //
  506. bSuccess = Authenticate(&hToken);
  507. if (bSuccess) {
  508. //
  509. // The user successfully authenticated, so unlock the session
  510. //
  511. Unlock();
  512. //
  513. // Tell the screen scraper we need a full dump of it's screen
  514. //
  515. m_Scraper->DisplayFullScreen();
  516. } else {
  517. //
  518. // Loop back around to the WaitForMultipleObjects so that
  519. // we can catch the close event if it occurred
  520. //
  521. NOTHING;
  522. }
  523. break;
  524. case CMD_KILLED:
  525. case CHANNEL_CLOSE_EVENT:
  526. //
  527. // Tell the Input Thread to exit
  528. //
  529. SetEvent(m_ThreadExitEvent);
  530. default:
  531. //
  532. // incase WAIT_FAILED, call GetLastError()
  533. //
  534. ASSERT( dwRetVal != WAIT_FAILED);
  535. m_bContinueSession = false;
  536. break;
  537. }
  538. }
  539. return;
  540. }
  541. void
  542. CSession::Shutdown(
  543. VOID
  544. )
  545. /*++
  546. Routine Description:
  547. This routine does the cleanup work for shutting down the session.
  548. Note: this routine does not free memory
  549. Arguments:
  550. None
  551. Return Value:
  552. None
  553. --*/
  554. {
  555. //
  556. // Shutdown the shell
  557. //
  558. if (m_Shell) {
  559. m_Shell->Shutdown();
  560. }
  561. //
  562. // If we started the input thread,
  563. // then shut it down
  564. //
  565. if (m_InputThreadHandle != INVALID_HANDLE_VALUE) {
  566. //
  567. // Wait for the thread to exit
  568. //
  569. WaitForSingleObject(
  570. m_InputThreadHandle,
  571. INFINITE
  572. );
  573. CloseHandle(m_InputThreadHandle);
  574. }
  575. }
  576. unsigned int
  577. CSession::InputThread(
  578. PVOID pParam
  579. )
  580. /*++
  581. Routine Description:
  582. This routine provides asynchronous support for handling
  583. user-input from the IoHandler to the session.
  584. Arguments:
  585. pParam - thread context
  586. Return Value:
  587. status
  588. --*/
  589. {
  590. BOOL bContinueSession;
  591. DWORD dwRetVal;
  592. CSession *session;
  593. HANDLE handles[2];
  594. //
  595. // default: listen
  596. //
  597. bContinueSession = TRUE;
  598. //
  599. // Get the session object
  600. //
  601. session = (CSession*)pParam;
  602. //
  603. // Assign the events to listen for
  604. //
  605. handles[0] = session->m_SacChannelHasNewDataEvent;
  606. handles[1] = session->m_ThreadExitEvent;
  607. //
  608. // While we should listen:
  609. //
  610. // 1. wait for a HasNewDataEvent from the SAC driver
  611. // 2. wait for a CloseEvent from the SAC driver
  612. //
  613. while ( bContinueSession ) {
  614. //
  615. // Wait for our events
  616. //
  617. dwRetVal = WaitForMultipleObjects(
  618. sizeof(handles)/sizeof(HANDLE),
  619. handles,
  620. FALSE,
  621. INFINITE
  622. );
  623. switch ( dwRetVal ) {
  624. case WAIT_OBJECT_0: {
  625. //
  626. // Read user-input from the channel
  627. //
  628. bContinueSession = session->m_Scraper->Read();
  629. break;
  630. }
  631. default:
  632. //
  633. // incase WAIT_FAILED, call GetLastError()
  634. //
  635. ASSERT(dwRetVal != WAIT_FAILED);
  636. //
  637. // An error has occured, stop listening
  638. //
  639. bContinueSession = FALSE;
  640. break;
  641. }
  642. }
  643. return 0;
  644. }