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.

1944 lines
42 KiB

  1. /*++
  2. Copyright (c) 1999-2001 Microsoft Corporation
  3. Module Name:
  4. secio.cpp
  5. Abstract:
  6. This file contains the implementation of the CSecurityIoHandler
  7. class which enapsulates the primary security elements used by
  8. the CSession class.
  9. TODO: this class needs to use a TermCap class to abstract the screen
  10. controls - currently, the class implicitly uses VT-UTF8
  11. Author:
  12. Brian Guarraci (briangu) 2001.
  13. Revision History:
  14. --*/
  15. #include <nt.h>
  16. #include <ntrtl.h>
  17. #include <nturtl.h>
  18. #include <windows.h>
  19. #include <process.h>
  20. #include "cmnhdr.h"
  21. #include "secio.h"
  22. #include "nullio.h"
  23. #include "sacmsg.h"
  24. #include "utils.h"
  25. #define VTUTF8_CLEAR_SCREEN L"\033[2J\033[0;0H"
  26. #define READ_BUFFER_LENGTH 512
  27. #define READ_BUFFER_SIZE (READ_BUFFER_LENGTH * sizeof(WCHAR))
  28. CSecurityIoHandler::CSecurityIoHandler(
  29. IN CIoHandler *LockedIoHandler,
  30. IN CIoHandler *UnlockedIoHandler
  31. ) : CLockableIoHandler(
  32. LockedIoHandler,
  33. UnlockedIoHandler
  34. )
  35. /*++
  36. Routine Description:
  37. Constructor
  38. Arguments:
  39. LockedIoHandler - the IoHandler to use when the channel is locked
  40. UnlockedIoHandler - the IoHandler to use when the channel is unlocked
  41. Return Value:
  42. N/A
  43. --*/
  44. {
  45. //
  46. // Lock the IoHandler so that the read/write routines
  47. // are disabled.
  48. //
  49. Lock();
  50. //
  51. // Validate that our Io Handler pointers are valid
  52. //
  53. // This way, we don't have to check everytime we want
  54. // to use them.
  55. //
  56. ASSERT(myLockedIoHandler != NULL);
  57. ASSERT(myUnlockedIoHandler != NULL);
  58. ASSERT(myIoHandler != NULL);
  59. //
  60. // initialize our internal lock event
  61. //
  62. m_InternalLockEvent = 0;
  63. //
  64. // init
  65. //
  66. m_StartedAuthentication = FALSE;
  67. }
  68. CSecurityIoHandler::~CSecurityIoHandler()
  69. /*++
  70. Routine Description:
  71. Desctructor
  72. Arguments:
  73. N/A
  74. Return Value:
  75. N/A
  76. --*/
  77. {
  78. //
  79. // Notify the remote user that we are shutting down the
  80. // command console session
  81. //
  82. WriteResourceMessage(SHUTDOWN_NOTICE);
  83. //
  84. // release the redraw handler
  85. //
  86. if (m_RedrawHandler) {
  87. delete m_RedrawHandler;
  88. }
  89. //
  90. // The CLockableIoHandler destructor deletes the IoHandlers for us.
  91. //
  92. NOTHING;
  93. //
  94. // If the TimeOut thread is running, then stop it
  95. //
  96. if ((m_TimeOutThreadHandle != INVALID_HANDLE_VALUE) &&
  97. (m_ThreadExitEvent != NULL)) {
  98. //
  99. // Tell the TimeOut Thread to exit
  100. //
  101. SetEvent(m_ThreadExitEvent);
  102. //
  103. // Wait for the thread to exit
  104. //
  105. WaitForSingleObject(
  106. m_TimeOutThreadHandle,
  107. INFINITE
  108. );
  109. }
  110. //
  111. // Close the internal lock event
  112. //
  113. if (m_InternalLockEvent) {
  114. CloseHandle(m_InternalLockEvent);
  115. }
  116. //
  117. // Close the thread exit handle
  118. //
  119. if (m_ThreadExitEvent != NULL) {
  120. CloseHandle(m_ThreadExitEvent);
  121. }
  122. //
  123. // Close the thread handle
  124. //
  125. if (m_TimeOutThreadHandle != INVALID_HANDLE_VALUE) {
  126. CloseHandle(m_TimeOutThreadHandle);
  127. }
  128. }
  129. CSecurityIoHandler*
  130. CSecurityIoHandler::Construct(
  131. IN SAC_CHANNEL_OPEN_ATTRIBUTES Attributes
  132. )
  133. /*++
  134. Routine Description:
  135. This routine constructs a security IoHandler connected
  136. to a channel with the specified attributes.
  137. Arguments:
  138. Attributes - the attributes of the new channel
  139. Return Value:
  140. Success - A ptr to a CSecurityIoHandler object.
  141. Failure - NULL
  142. --*/
  143. {
  144. BOOL bSuccess;
  145. CSecurityIoHandler *IoHandler;
  146. CIoHandler *SacIoHandler;
  147. CIoHandler *NullIoHandler;
  148. //
  149. // default: failed to construct
  150. //
  151. bSuccess = FALSE;
  152. IoHandler = NULL;
  153. SacIoHandler = NULL;
  154. NullIoHandler = NULL;
  155. do {
  156. BOOL bStatus;
  157. //
  158. // Validate the LockEvent for the timeout thread
  159. //
  160. ASSERT(Attributes.LockEvent != NULL);
  161. if (Attributes.LockEvent == NULL) {
  162. break;
  163. }
  164. ASSERT(Attributes.LockEvent != INVALID_HANDLE_VALUE);
  165. if (Attributes.LockEvent == INVALID_HANDLE_VALUE) {
  166. break;
  167. }
  168. //
  169. // Validate the CloseEvent for the WaitForInput thread
  170. //
  171. ASSERT(Attributes.CloseEvent != NULL);
  172. if (Attributes.CloseEvent == NULL) {
  173. break;
  174. }
  175. ASSERT(Attributes.CloseEvent != INVALID_HANDLE_VALUE);
  176. if (Attributes.CloseEvent == INVALID_HANDLE_VALUE) {
  177. break;
  178. }
  179. //
  180. // Validate the RedrawEvent for the Redraw IoHandler
  181. //
  182. ASSERT(Attributes.RedrawEvent != NULL);
  183. if (Attributes.RedrawEvent == NULL) {
  184. break;
  185. }
  186. ASSERT(Attributes.RedrawEvent != INVALID_HANDLE_VALUE);
  187. if (Attributes.RedrawEvent == INVALID_HANDLE_VALUE) {
  188. break;
  189. }
  190. //
  191. // Attempt to open a SAC channel
  192. //
  193. SacIoHandler = CSacIoHandler::Construct(Attributes);
  194. //
  195. // If we failed to open the SAC channel,
  196. // then notify the caller that we failed by returning null
  197. //
  198. if (SacIoHandler == NULL) {
  199. break;
  200. }
  201. //
  202. // Get the Null Io Handler to be the locked IoHandler
  203. //
  204. NullIoHandler = new CNullIoHandler();
  205. //
  206. // Create a new SAC IoHandler
  207. //
  208. IoHandler = new CSecurityIoHandler(
  209. NullIoHandler,
  210. SacIoHandler
  211. );
  212. //
  213. // Create the event we will use to signal that a timeout
  214. // occured while we were trying to authenticate a user
  215. //
  216. IoHandler->m_InternalLockEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
  217. ASSERT(IoHandler->m_InternalLockEvent);
  218. if (IoHandler->m_InternalLockEvent == 0) {
  219. break;
  220. }
  221. //
  222. // Keep the LockEvent for the timeout thread
  223. // Keep the CloseEvent for the WaitForInput thread
  224. //
  225. IoHandler->m_CloseEvent = Attributes.CloseEvent;
  226. IoHandler->m_LockEvent = Attributes.LockEvent;
  227. IoHandler->m_RedrawEvent = Attributes.RedrawEvent;
  228. //
  229. // Create the event used to signal the threads to exit
  230. //
  231. IoHandler->m_ThreadExitEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
  232. if (IoHandler->m_ThreadExitEvent == NULL) {
  233. break;
  234. }
  235. //
  236. // Start the timeout thread if we need to
  237. //
  238. bStatus = IoHandler->InitializeTimeOutThread();
  239. if (! bStatus) {
  240. break;
  241. }
  242. //
  243. // Create handler for redraw events
  244. //
  245. IoHandler->m_RedrawHandler = CRedrawHandler::Construct(
  246. IoHandler,
  247. Attributes.RedrawEvent
  248. );
  249. ASSERT(IoHandler->m_RedrawHandler);
  250. if (IoHandler->m_RedrawHandler == NULL) {
  251. break;
  252. }
  253. //
  254. // we were successful
  255. //
  256. bSuccess = TRUE;
  257. } while ( FALSE );
  258. //
  259. // if we were not successful
  260. // then clean up
  261. //
  262. if (! bSuccess) {
  263. //
  264. // Note: we do not need to clean up the Lock, Close, and Redraw events
  265. // because we do not own them. Also, we do not need
  266. // to clean up the NullIo and SacIo IoHandlers because
  267. // they are cleaned up by the LockIo parent class.
  268. //
  269. if (IoHandler) {
  270. delete IoHandler;
  271. IoHandler = NULL;
  272. }
  273. }
  274. return IoHandler;
  275. }
  276. BOOL
  277. CSecurityIoHandler::Write(
  278. PBYTE Buffer,
  279. ULONG BufferSize
  280. )
  281. /*++
  282. Routine Description:
  283. This routine implements the IoHandler Write behavior.
  284. Arguments:
  285. (see iohandler)
  286. Return Value:
  287. (see iohandler)
  288. --*/
  289. {
  290. //
  291. // Pass through to the secured Io Handler
  292. //
  293. return myIoHandler->Write(
  294. Buffer,
  295. BufferSize
  296. );
  297. }
  298. BOOL
  299. CSecurityIoHandler::Flush(
  300. VOID
  301. )
  302. /*++
  303. Routine Description:
  304. This routine implements the IoHandler Flush behavior.
  305. Arguments:
  306. (see iohandler)
  307. Return Value:
  308. (see iohandler)
  309. --*/
  310. {
  311. //
  312. // Pass through to the secured Io Handler
  313. //
  314. return myIoHandler->Flush();
  315. }
  316. BOOL
  317. CSecurityIoHandler::Read(
  318. PBYTE Buffer,
  319. ULONG BufferSize,
  320. PULONG ByteCount
  321. )
  322. /*++
  323. Routine Description:
  324. This routine implements the IoHandler Read behavior and
  325. resets the timeout counter when ever there is a successful
  326. read.
  327. Arguments:
  328. (see iohandler)
  329. Return Value:
  330. (see iohandler)
  331. --*/
  332. {
  333. BOOL bSuccess;
  334. //
  335. // Pass through to the secured Io Handler
  336. //
  337. // if this iohandler is locked,
  338. // then the caller will be reading from the NullIoHandler
  339. // else they will read from the UnlockedIoHandler
  340. //
  341. bSuccess = myIoHandler->Read(
  342. Buffer,
  343. BufferSize,
  344. ByteCount
  345. );
  346. //
  347. // If the sesssion received new user input,
  348. // then reset the timeout counter
  349. //
  350. if (*ByteCount > 0) {
  351. ResetTimeOut();
  352. }
  353. return bSuccess;
  354. }
  355. BOOL
  356. CSecurityIoHandler::ReadUnlockedIoHandler(
  357. PBYTE Buffer,
  358. ULONG BufferSize,
  359. PULONG ByteCount
  360. )
  361. /*++
  362. Routine Description:
  363. This routine reads a character from the unlocked io hander
  364. so that we can authenticate the user while the scraper still
  365. uses the LockedIohandler.
  366. resets the timeout counter when ever there is a successful
  367. read.
  368. Arguments:
  369. (see iohandler)
  370. Return Value:
  371. (see iohandler)
  372. --*/
  373. {
  374. BOOL bSuccess;
  375. //
  376. // Pass through to the secured Io Handler
  377. //
  378. bSuccess = myUnlockedIoHandler->Read(
  379. Buffer,
  380. BufferSize,
  381. ByteCount
  382. );
  383. //
  384. // If the sesssion received new user input,
  385. // then reset the timeout counter
  386. //
  387. if (*ByteCount > 0) {
  388. ResetTimeOut();
  389. }
  390. return bSuccess;
  391. }
  392. BOOL
  393. CSecurityIoHandler::HasNewData(
  394. PBOOL InputWaiting
  395. )
  396. /*++
  397. Routine Description:
  398. This routine implements the IoHandler HasNewData behavior.
  399. Arguments:
  400. (see iohandler)
  401. Return Value:
  402. (see iohandler)
  403. --*/
  404. {
  405. //
  406. // Pass through to the secured Io Handler
  407. //
  408. return myIoHandler->HasNewData(InputWaiting);
  409. }
  410. BOOL
  411. CSecurityIoHandler::WriteResourceMessage(
  412. IN INT MsgId
  413. )
  414. /*++
  415. Routine Description:
  416. This routine writes a resource string message to
  417. the Unlocked ioHandler.
  418. Arguments:
  419. MsgId - the id of the message to write
  420. Return Value:
  421. TRUE - the message was loaded and written
  422. FALSE - failed
  423. --*/
  424. {
  425. UNICODE_STRING UnicodeString = {0};
  426. BOOL bSuccess;
  427. //
  428. // Default: failed
  429. //
  430. bSuccess = FALSE;
  431. //
  432. // Attempt to load the string and write it
  433. //
  434. do {
  435. if ( LoadStringResource(&UnicodeString, MsgId) ) {
  436. //
  437. // Terminate the string at the %0 marker, if it is present
  438. //
  439. if( wcsstr( UnicodeString.Buffer, L"%0" ) ) {
  440. *((PWCHAR)wcsstr( UnicodeString.Buffer, L"%0" )) = L'\0';
  441. }
  442. //
  443. // Write the message
  444. //
  445. bSuccess = m_RedrawHandler->Write(
  446. (PUCHAR)UnicodeString.Buffer,
  447. (ULONG)(wcslen( UnicodeString.Buffer) * sizeof(WCHAR))
  448. );
  449. if (!bSuccess) {
  450. break;
  451. }
  452. bSuccess = m_RedrawHandler->Flush();
  453. }
  454. } while ( FALSE );
  455. return bSuccess;
  456. }
  457. BOOL
  458. CSecurityIoHandler::LoadStringResource(
  459. IN PUNICODE_STRING pUnicodeString,
  460. IN INT MsgId
  461. )
  462. /*++
  463. Routine Description:
  464. This is a simple implementation of LoadString().
  465. Arguments:
  466. usString - Returns the resource string.
  467. MsgId - Supplies the message id of the resource string.
  468. Return Value:
  469. FALSE - Failure.
  470. TRUE - Success.
  471. --*/
  472. {
  473. NTSTATUS Status;
  474. PMESSAGE_RESOURCE_ENTRY MessageEntry;
  475. ANSI_STRING AnsiString;
  476. Status = RtlFindMessage( NtCurrentPeb()->ImageBaseAddress,
  477. (ULONG_PTR) RT_MESSAGETABLE,
  478. 0,
  479. (ULONG)MsgId,
  480. &MessageEntry
  481. );
  482. if (!NT_SUCCESS( Status )) {
  483. return FALSE;
  484. }
  485. if (!(MessageEntry->Flags & MESSAGE_RESOURCE_UNICODE)) {
  486. RtlInitAnsiString( &AnsiString, (PCSZ)&MessageEntry->Text[ 0 ] );
  487. Status = RtlAnsiStringToUnicodeString( pUnicodeString, &AnsiString, TRUE );
  488. if (!NT_SUCCESS( Status )) {
  489. return FALSE;
  490. }
  491. } else {
  492. RtlCreateUnicodeString(pUnicodeString, (PWSTR)MessageEntry->Text);
  493. }
  494. return TRUE;
  495. }
  496. BOOL
  497. CSecurityIoHandler::AuthenticateCredentials(
  498. IN PWSTR UserName,
  499. IN PWSTR DomainName,
  500. IN PWSTR Password,
  501. OUT PHANDLE pUserToken
  502. )
  503. /*++
  504. Routine Description:
  505. This routine will attempt to authenticate the supplied credentials.
  506. Arguments:
  507. UserName - Supplied UserName
  508. DomainName - Supplied DomainName
  509. Password - Supplied Password
  510. pUserToken - Holds the valid token for the authenticated user
  511. credentials.
  512. Return Value:
  513. TRUE - Credentials successfully authenticated.
  514. FALSE - Credentials failed to authenticate.
  515. Security:
  516. interface: exposes user input to LogonUser()
  517. --*/
  518. {
  519. BOOL b;
  520. //
  521. // Notify the user that we are attempting to authenticate
  522. //
  523. WriteResourceMessage(LOGIN_IN_PROGRESS);
  524. //
  525. // Try the authentication.
  526. //
  527. b = LogonUser( UserName,
  528. DomainName,
  529. Password,
  530. LOGON32_LOGON_INTERACTIVE,
  531. LOGON32_PROVIDER_DEFAULT,
  532. pUserToken );
  533. if (b) {
  534. //
  535. // Reset the timeout counter before we start the thread
  536. //
  537. ResetTimeOut();
  538. } else {
  539. //
  540. // Wait 3 seconds before returning control to user in
  541. // order to slow iterative attacks
  542. //
  543. Sleep(3000);
  544. //
  545. // Notify the user that the attempt failed
  546. //
  547. WriteResourceMessage(LOGIN_FAILURE);
  548. //
  549. // Wait for a key press
  550. //
  551. WaitForUserInput(TRUE);
  552. }
  553. return b;
  554. }
  555. BOOL
  556. CSecurityIoHandler::RetrieveCredential(
  557. OUT PWSTR String,
  558. IN ULONG StringLength,
  559. IN BOOL EchoClearText
  560. )
  561. /*++
  562. Routine Description:
  563. This routine will request credentials from the user. Those
  564. credentials are then returned to the caller.
  565. Arguments:
  566. String - on success, contains the credential
  567. StringLength - the # of WCHARS (length) in the string (includes NULL termination)
  568. EchoClearText - TRUE: echo user input in clear text
  569. FALSE: echo user input as '*'
  570. Return Value:
  571. TRUE - Credential recieved.
  572. FALSE - Something failed when we were trying to get credentials
  573. from the user.
  574. Security:
  575. interface: external input
  576. echos user input
  577. --*/
  578. {
  579. PWCHAR buffer;
  580. ULONG bufferSize;
  581. ULONG i, j;
  582. BOOLEAN Done = FALSE;
  583. BOOL bSuccess;
  584. //
  585. // validate parameters
  586. //
  587. if (! String) {
  588. return FALSE;
  589. }
  590. if (StringLength < 1) {
  591. return FALSE;
  592. }
  593. //
  594. // default: failed
  595. //
  596. bSuccess = FALSE;
  597. //
  598. // allocate the buffer we'll use to read the channel
  599. //
  600. buffer = new WCHAR[READ_BUFFER_LENGTH];
  601. //
  602. // default: start at the first character
  603. //
  604. i = 0;
  605. //
  606. // default: we need to read user input
  607. //
  608. Done = FALSE;
  609. //
  610. // Attempt to retrieve the credential
  611. //
  612. while ( !Done ) {
  613. //
  614. // Wait until the user inputs something
  615. //
  616. bSuccess = WaitForUserInput(FALSE);
  617. if (!bSuccess) {
  618. Done = TRUE;
  619. continue;
  620. }
  621. //
  622. // Read what the user input
  623. //
  624. //
  625. // we should be in a locked state now
  626. // which implies we are using the unlocked
  627. // io handler - the scraper is using the locked one
  628. //
  629. ASSERT(myLockedIoHandler == myIoHandler);
  630. bSuccess = ReadUnlockedIoHandler(
  631. (PUCHAR)buffer,
  632. READ_BUFFER_SIZE,
  633. &bufferSize
  634. );
  635. if (bSuccess) {
  636. //
  637. // We have received at least one character
  638. // hence by setting this to true, we enable
  639. // the internal lock event to succeed in
  640. // resetting the authentication attempt
  641. // that is, if the user starts to authenticate
  642. // and stops before finishing, the timer will
  643. // fire and reset the authentication attempt
  644. //
  645. m_StartedAuthentication = TRUE;
  646. //
  647. // Process the characters he gave us.
  648. //
  649. // Note: the buffer contains WCHARs, hence we need to
  650. // divide the returned buffersize by sizeof(WCHAR) in
  651. // order to get the # of wchars to process.
  652. //
  653. for ( j = 0; j < bufferSize/sizeof(WCHAR); j++ ) {
  654. //
  655. // stop if:
  656. //
  657. // we reached the end of the Credentials buffer (not including the NULL)
  658. // we received a CR || LF
  659. //
  660. if ( (i >= (StringLength-1)) || (buffer[j] == 0x0D) || (buffer[j] == 0x0A) ) {
  661. Done = TRUE;
  662. break;
  663. }
  664. //
  665. // handle user input
  666. //
  667. if( buffer[j] == '\b' ) {
  668. //
  669. // The user gave us a backspace. We should cover up the
  670. // character on the screen, then backup our index so we
  671. // essentially forget the last thing he gave us.
  672. //
  673. // If the very first thing the user did was type in a backspace,
  674. // no need to back anything up.
  675. //
  676. if( i > 0 ) {
  677. i--;
  678. String[i] = L'\0';
  679. bSuccess = m_RedrawHandler->Write(
  680. (PUCHAR)L"\b \b",
  681. (ULONG)(wcslen(L"\b \b") * sizeof(WCHAR))
  682. );
  683. if (!bSuccess) {
  684. //
  685. // write failed: exit
  686. //
  687. Done = TRUE;
  688. }
  689. }
  690. } else if (buffer[j] < ' ') {
  691. //
  692. // If the character is less than ' ' (a control char),
  693. // then ignore it
  694. //
  695. NOTHING;
  696. } else {
  697. //
  698. // It was a valid character: remember the input and echo it back
  699. // to the user.
  700. //
  701. String[i] = buffer[j];
  702. i++;
  703. //
  704. // Echo according to caller specifications
  705. //
  706. bSuccess = m_RedrawHandler->Write(
  707. EchoClearText ? (PUCHAR)&buffer[j] : (PUCHAR)L"*",
  708. sizeof(WCHAR)
  709. );
  710. if (!bSuccess) {
  711. //
  712. // write failed: exit
  713. //
  714. Done = TRUE;
  715. }
  716. }
  717. }
  718. if (bSuccess) {
  719. //
  720. // Flush any text echoing we've done.
  721. //
  722. bSuccess = m_RedrawHandler->Flush();
  723. if (!bSuccess) {
  724. //
  725. // write failed: exit
  726. //
  727. Done = TRUE;
  728. }
  729. }
  730. } else {
  731. //
  732. // read failed: exit
  733. //
  734. Done = TRUE;
  735. }
  736. }
  737. //
  738. // Terminate the credential
  739. //
  740. String[i] = UNICODE_NULL;
  741. //
  742. // release the read buffer
  743. //
  744. delete [] buffer;
  745. return bSuccess;
  746. }
  747. BOOL
  748. CSecurityIoHandler::RetrieveCredentials(
  749. IN OUT PWSTR UserName,
  750. IN ULONG UserNameLength,
  751. IN OUT PWSTR DomainName,
  752. IN ULONG DomainNameLength,
  753. IN OUT PWSTR Password,
  754. IN ULONG PasswordLength
  755. )
  756. /*++
  757. Routine Description:
  758. This routine will request credentials from the user. Those
  759. credentials are then returned to the caller.
  760. Arguments:
  761. UserName - Buffer to hold the UserName
  762. UserNameLength - Length of the UserName buffer
  763. DomainName - Buffer to hold the DomainName
  764. DomainNameLength - Length of the DomainName buffer
  765. Password - Buffer to hold the Password
  766. PasswordLength - Length of the Password buffer
  767. Return Value:
  768. TRUE - Credentials recieved.
  769. FALSE - Something failed when we were trying to get credentials
  770. from the user.
  771. --*/
  772. {
  773. BOOL HaveDomainName;
  774. BOOL bSuccess;
  775. //
  776. // Initialize the flag that we use to keep track
  777. // of when the user first starts to authenticate.
  778. // that is, after they enter at least one character
  779. // they have started to authenticate.
  780. //
  781. m_StartedAuthentication = FALSE;
  782. //
  783. // Initialize our redraw screen
  784. //
  785. m_RedrawHandler->Reset();
  786. //
  787. // Clear the screen
  788. //
  789. m_RedrawHandler->Write(
  790. (PUCHAR)VTUTF8_CLEAR_SCREEN,
  791. (ULONG)(wcslen( VTUTF8_CLEAR_SCREEN ) * sizeof(WCHAR))
  792. );
  793. m_RedrawHandler->Flush();
  794. //
  795. // Put up the login banner.
  796. //
  797. if (! WriteResourceMessage(LOGIN_BANNER) ) {
  798. return FALSE;
  799. }
  800. //
  801. // Prompt for user name.
  802. //
  803. if (! WriteResourceMessage(USERNAME_PROMPT) ) {
  804. return FALSE;
  805. }
  806. if ( UserName[0] != UNICODE_NULL ) {
  807. //
  808. // We were supplied a UserName. Put that up and proceed.
  809. //
  810. m_RedrawHandler->Write(
  811. (PUCHAR)UserName,
  812. (ULONG)(wcslen( UserName ) * sizeof(WCHAR))
  813. );
  814. m_RedrawHandler->Flush();
  815. //
  816. // If we were given the username, we conclude that
  817. // they gave us the domain name as well. We need
  818. // to do this since the domain name may be empty
  819. // and we automatlically conclude that because the
  820. // domain name is empty we need to retrieve it.
  821. //
  822. HaveDomainName = TRUE;
  823. } else {
  824. //
  825. // Retrieve the UserName.
  826. //
  827. bSuccess = RetrieveCredential(
  828. UserName,
  829. UserNameLength,
  830. TRUE
  831. );
  832. if (!bSuccess) {
  833. return FALSE;
  834. }
  835. //
  836. // We need to retrieve the domain name too.
  837. //
  838. HaveDomainName = FALSE;
  839. }
  840. //
  841. //
  842. //
  843. m_RedrawHandler->Write(
  844. (PUCHAR)L"\r\n",
  845. (ULONG)(wcslen(L"\r\n") * sizeof(WCHAR))
  846. );
  847. m_RedrawHandler->Flush();
  848. //
  849. // Prompt for domain name
  850. //
  851. if (! WriteResourceMessage(DOMAINNAME_PROMPT) ) {
  852. return FALSE;
  853. }
  854. //
  855. // Prompt for domain name.
  856. //
  857. if ( HaveDomainName ) {
  858. //
  859. // We were supplied a username. Put that up and proceed.
  860. //
  861. m_RedrawHandler->Write(
  862. (PUCHAR)DomainName,
  863. (ULONG)(wcslen( DomainName ) * sizeof(WCHAR))
  864. );
  865. m_RedrawHandler->Flush();
  866. } else {
  867. //
  868. // Retrieve the DomainName.
  869. //
  870. bSuccess = RetrieveCredential(
  871. DomainName,
  872. DomainNameLength,
  873. TRUE
  874. );
  875. if (!bSuccess) {
  876. return FALSE;
  877. }
  878. //
  879. // If user entered a blank domain, force it to '.'
  880. // which implies local machine domain
  881. //
  882. if (wcslen(DomainName) == 0) {
  883. wsprintf(
  884. DomainName,
  885. L"."
  886. );
  887. }
  888. }
  889. //
  890. //
  891. //
  892. m_RedrawHandler->Write(
  893. (PUCHAR)L"\r\n",
  894. (ULONG)(wcslen(L"\r\n") * sizeof(WCHAR))
  895. );
  896. //
  897. // Prompt for password.
  898. //
  899. if (! WriteResourceMessage(PASSWORD_PROMPT) ) {
  900. return FALSE;
  901. }
  902. //
  903. // Retrieve the Password.
  904. //
  905. bSuccess = RetrieveCredential(
  906. Password,
  907. PasswordLength,
  908. FALSE
  909. );
  910. if (!bSuccess) {
  911. return FALSE;
  912. }
  913. //
  914. //
  915. //
  916. m_RedrawHandler->Write(
  917. (PUCHAR)L"\r\n",
  918. (ULONG)(wcslen(L"\r\n") * sizeof(WCHAR))
  919. );
  920. m_RedrawHandler->Flush();
  921. return TRUE;
  922. }
  923. VOID
  924. CSecurityIoHandler::ResetTimeOut(
  925. VOID
  926. )
  927. /*++
  928. Routine Description:
  929. This routine resets the StartTickCount to 0
  930. Arguments:
  931. None
  932. Return Value:
  933. None
  934. --*/
  935. {
  936. ULONG TimerTick;
  937. //
  938. // Get the current timer tick
  939. //
  940. TimerTick = GetTickCount();
  941. //
  942. // Reset the timeout counter by making the current timer tick
  943. // the starting tick count
  944. //
  945. InterlockedExchange(&m_StartTickCount, TimerTick);
  946. #if ENABLE_EVENT_DEBUG
  947. {
  948. WCHAR blob[256];
  949. wsprintf(blob,L"ResetTimeOut\n");
  950. OutputDebugString(blob);
  951. }
  952. #endif
  953. }
  954. BOOL
  955. CSecurityIoHandler::TimeOutOccured(
  956. VOID
  957. )
  958. /*++
  959. Routine Description:
  960. This routine determines if the specified timeout interval
  961. has been reached. It takes the specified TickCount and
  962. compares it to the m_StartTickCount. If the interval equals
  963. or exceeds the timeout interval, then a timeout has occured.
  964. Arguments:
  965. None
  966. Return Value:
  967. TRUE - The timeout interval has been reached
  968. FALSE - otherwise
  969. --*/
  970. {
  971. BOOL bTimedOut;
  972. DWORD DeltaT;
  973. //
  974. // default: we did not time out
  975. //
  976. bTimedOut = FALSE;
  977. //
  978. // See if we timed out
  979. //
  980. DeltaT = GetAndComputeTickCountDeltaT(m_StartTickCount);
  981. if (DeltaT >= m_TimeOutInterval) {
  982. //
  983. // Reset the timeout counter
  984. //
  985. ResetTimeOut();
  986. //
  987. // We timed out
  988. //
  989. bTimedOut = TRUE;
  990. #if ENABLE_EVENT_DEBUG
  991. {
  992. WCHAR blob[256];
  993. wsprintf(blob,L"TimeOutOccured\n");
  994. OutputDebugString(blob);
  995. }
  996. #endif
  997. }
  998. return bTimedOut;
  999. }
  1000. BOOL
  1001. CSecurityIoHandler::InitializeTimeOutThread(
  1002. VOID
  1003. )
  1004. /*++
  1005. Routine Description:
  1006. This routine initializes the timeout thread if timeout
  1007. behavior is enabled.
  1008. Arguments:
  1009. None
  1010. Return Value:
  1011. TRUE Success
  1012. FALSE Otherwise
  1013. --*/
  1014. {
  1015. BOOL bSuccess;
  1016. //
  1017. // default: failed to init
  1018. //
  1019. bSuccess = FALSE;
  1020. //
  1021. // default: we do not have a timeout thread
  1022. //
  1023. m_TimeOutThreadHandle = INVALID_HANDLE_VALUE;
  1024. //
  1025. // determine if we need a timeout thread
  1026. // if we do, then set one up
  1027. //
  1028. do {
  1029. //
  1030. // If the timeout behavior is disabled,
  1031. // then we are done.
  1032. //
  1033. if (IsTimeOutEnabled() == FALSE) {
  1034. //
  1035. // No Initialization required
  1036. //
  1037. bSuccess = TRUE;
  1038. break;
  1039. }
  1040. //
  1041. // determine the time out interval
  1042. //
  1043. if (GetTimeOutInterval(&m_TimeOutInterval) == TRUE) {
  1044. //
  1045. // Reset the timeout counter before we start the thread
  1046. //
  1047. ResetTimeOut();
  1048. //
  1049. // Create thread to handle Input
  1050. //
  1051. m_TimeOutThreadHandle = (HANDLE)_beginthreadex(
  1052. NULL,
  1053. 0,
  1054. CSecurityIoHandler::TimeOutThread,
  1055. this,
  1056. 0,
  1057. (unsigned int*)&m_TimeOutThreadTID
  1058. );
  1059. if (m_TimeOutThreadHandle == INVALID_HANDLE_VALUE) {
  1060. break;
  1061. }
  1062. //
  1063. // we successfully started the thread
  1064. //
  1065. bSuccess = TRUE;
  1066. }
  1067. } while ( FALSE );
  1068. return bSuccess;
  1069. }
  1070. BOOL
  1071. CSecurityIoHandler::GetTimeOutInterval(
  1072. OUT PULONG TimeOutDuration
  1073. )
  1074. /*++
  1075. Routine Description:
  1076. This routine determines the timeout interval.
  1077. It attempts to read the registry and use a specified
  1078. value from there, or defaults.
  1079. Arguments:
  1080. TimeOutDuration - the determined timeout interval
  1081. Return Value:
  1082. TRUE - TimeOutDuration is valid
  1083. FALSE - otherwise
  1084. Security:
  1085. interface: registry
  1086. --*/
  1087. {
  1088. DWORD rc;
  1089. HKEY hKey;
  1090. DWORD DWord;
  1091. DWORD dwsize;
  1092. DWORD DataType;
  1093. //
  1094. // See if the user gave us a registry key to define the timeout duration
  1095. //
  1096. rc = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  1097. SACSVR_PARAMETERS_KEY,
  1098. 0,
  1099. KEY_READ,
  1100. &hKey );
  1101. if( rc == NO_ERROR ) {
  1102. dwsize = sizeof(DWORD);
  1103. rc = RegQueryValueEx(
  1104. hKey,
  1105. SACSVR_TIMEOUT_INTERVAL_VALUE,
  1106. NULL,
  1107. &DataType,
  1108. (LPBYTE)&DWord,
  1109. &dwsize );
  1110. RegCloseKey( hKey );
  1111. if ((rc == NO_ERROR) &&
  1112. (DataType == REG_DWORD) &&
  1113. (dwsize == sizeof(DWORD))
  1114. ) {
  1115. //
  1116. // Convert the specified timeout from minutes --> ms
  1117. //
  1118. *TimeOutDuration = DWord * (60 * 1000);
  1119. //
  1120. // A timeout interval of 0 is not allowed, default.
  1121. //
  1122. if (*TimeOutDuration == 0) {
  1123. *TimeOutDuration = DEFAULT_TIME_OUT_INTERVAL;
  1124. }
  1125. //
  1126. // clamp the timeout interval to a reasonable value
  1127. //
  1128. if (*TimeOutDuration > MAX_TIME_OUT_INTERVAL) {
  1129. *TimeOutDuration = MAX_TIME_OUT_INTERVAL;
  1130. }
  1131. return TRUE;
  1132. }
  1133. }
  1134. //
  1135. // Default: timeout duration
  1136. //
  1137. *TimeOutDuration = DEFAULT_TIME_OUT_INTERVAL;
  1138. return TRUE;
  1139. }
  1140. BOOL
  1141. CSecurityIoHandler::IsTimeOutEnabled(
  1142. VOID
  1143. )
  1144. /*++
  1145. Routine Description:
  1146. This routine determines if the timeout behavior is enabled
  1147. by the system.
  1148. Arguments:
  1149. None.
  1150. Return Value:
  1151. TRUE - timeout behavior is enabled
  1152. FALSE - otherwise
  1153. Security:
  1154. interface: registry
  1155. --*/
  1156. {
  1157. DWORD rc;
  1158. HKEY hKey;
  1159. DWORD DWord;
  1160. DWORD dwsize;
  1161. DWORD DataType;
  1162. //
  1163. // See if the user gave us a registry key to disable the timeout behavior
  1164. //
  1165. rc = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  1166. SACSVR_PARAMETERS_KEY,
  1167. 0,
  1168. KEY_READ,
  1169. &hKey );
  1170. if( rc == NO_ERROR ) {
  1171. dwsize = sizeof(DWORD);
  1172. rc = RegQueryValueEx(
  1173. hKey,
  1174. SACSVR_TIMEOUT_DISABLED_VALUE,
  1175. NULL,
  1176. &DataType,
  1177. (LPBYTE)&DWord,
  1178. &dwsize );
  1179. RegCloseKey( hKey );
  1180. if ((rc == NO_ERROR) &&
  1181. (DataType == REG_DWORD) &&
  1182. (dwsize == sizeof(DWORD))
  1183. ) {
  1184. return DWord == 1 ? FALSE : TRUE;
  1185. }
  1186. }
  1187. //
  1188. // default: timeout is enabled
  1189. //
  1190. return TRUE;
  1191. }
  1192. unsigned int
  1193. CSecurityIoHandler::TimeOutThread(
  1194. PVOID pParam
  1195. )
  1196. /*++
  1197. Routine Description:
  1198. This routine is a the timeout management thread.
  1199. When the Timeout interval is reached, this routine
  1200. fires the lock event and causes the session to perform
  1201. its locking behavior.
  1202. Arguments:
  1203. pParam - thread context
  1204. Return Value:
  1205. thread return value
  1206. --*/
  1207. {
  1208. CSecurityIoHandler *IoHandler;
  1209. BOOL bContinueSession;
  1210. DWORD dwRetVal;
  1211. DWORD dwPollInterval;
  1212. HANDLE handles[2];
  1213. ULONG HandleCount;
  1214. BOOL bRedrawEventSignaled;
  1215. enum {
  1216. CHANNEL_THREAD_EXIT_EVENT = WAIT_OBJECT_0,
  1217. CHANNEL_REDRAW_EVENT
  1218. };
  1219. //
  1220. // Get the session object
  1221. //
  1222. IoHandler = (CSecurityIoHandler*)pParam;
  1223. //
  1224. // Assign the events to listen for
  1225. //
  1226. handles[0] = IoHandler->m_ThreadExitEvent;
  1227. handles[1] = IoHandler->m_RedrawEvent;
  1228. //
  1229. // default: listen
  1230. //
  1231. bContinueSession = TRUE;
  1232. //
  1233. // wait on the redraw event
  1234. //
  1235. bRedrawEventSignaled = FALSE;
  1236. //
  1237. // Poll Interval = 1 second
  1238. //
  1239. dwPollInterval = 1000;
  1240. //
  1241. // While we should listen...
  1242. //
  1243. while ( bContinueSession ) {
  1244. HandleCount = bRedrawEventSignaled ? 1 : 2;
  1245. //
  1246. // Wait for our exit event
  1247. //
  1248. dwRetVal = WaitForMultipleObjects(
  1249. HandleCount,
  1250. handles,
  1251. FALSE,
  1252. dwPollInterval
  1253. );
  1254. switch ( dwRetVal ) {
  1255. case CHANNEL_REDRAW_EVENT:
  1256. //
  1257. // reset the timeout if someone switches back to a channel
  1258. //
  1259. IoHandler->ResetTimeOut();
  1260. //
  1261. // We don't need to waint on this event again until it clears
  1262. //
  1263. bRedrawEventSignaled = TRUE;
  1264. break;
  1265. case WAIT_TIMEOUT: {
  1266. //
  1267. // Check for timeout
  1268. //
  1269. if (IoHandler->TimeOutOccured()) {
  1270. //
  1271. // set the lock event causing
  1272. // the command console session to lock.
  1273. //
  1274. SetEvent(IoHandler->m_LockEvent);
  1275. //
  1276. // Set the internal lock event
  1277. //
  1278. SetEvent(IoHandler->m_InternalLockEvent);
  1279. }
  1280. //
  1281. // Wait until the event clears by looking
  1282. // for a WAIT_TIMEOUT
  1283. //
  1284. dwRetVal = WaitForSingleObject(
  1285. IoHandler->m_RedrawEvent,
  1286. 0
  1287. );
  1288. //
  1289. // Check the wait result
  1290. //
  1291. switch (dwRetVal) {
  1292. case WAIT_TIMEOUT:
  1293. //
  1294. // It's ok to wait for this event again
  1295. //
  1296. bRedrawEventSignaled = FALSE;
  1297. break;
  1298. default:
  1299. ASSERT (dwRetVal != WAIT_FAILED);
  1300. if (dwRetVal == WAIT_FAILED) {
  1301. bContinueSession = false;
  1302. }
  1303. break;
  1304. }
  1305. break;
  1306. }
  1307. case CHANNEL_THREAD_EXIT_EVENT:
  1308. default:
  1309. //
  1310. // incase WAIT_FAILED, call GetLastError()
  1311. //
  1312. ASSERT(dwRetVal != WAIT_FAILED);
  1313. //
  1314. // An error has occured, stop listening
  1315. //
  1316. bContinueSession = FALSE;
  1317. break;
  1318. }
  1319. }
  1320. return 0;
  1321. }
  1322. BOOL
  1323. CSecurityIoHandler::WaitForUserInput(
  1324. IN BOOL Consume
  1325. )
  1326. /*++
  1327. Routine Description:
  1328. This routine blocks waiting for user input.
  1329. Arguments:
  1330. Consume - if TRUE, this routine eats the character that caused
  1331. the the channel to have new data.
  1332. Return Value:
  1333. TRUE - no errors
  1334. FALSE - otherwise
  1335. --*/
  1336. {
  1337. BOOL bSuccess;
  1338. DWORD dwRetVal;
  1339. BOOL bHasNewData;
  1340. BOOL done;
  1341. HANDLE handles[2];
  1342. enum {
  1343. CHANNEL_CLOSE_EVENT = WAIT_OBJECT_0,
  1344. CHANNEL_LOCK_EVENT
  1345. };
  1346. //
  1347. // Assign the events to listen for
  1348. //
  1349. handles[0] = m_CloseEvent;
  1350. handles[1] = m_InternalLockEvent;
  1351. //
  1352. // Default: we succeeded
  1353. //
  1354. bSuccess = TRUE;
  1355. //
  1356. // Default: we loop
  1357. //
  1358. done = FALSE;
  1359. //
  1360. // Wait for a key press
  1361. //
  1362. while (!done) {
  1363. dwRetVal = WaitForMultipleObjects(
  1364. sizeof(handles) / sizeof(handles[0]),
  1365. handles,
  1366. FALSE,
  1367. 20 // 20ms
  1368. );
  1369. switch(dwRetVal) {
  1370. case CHANNEL_CLOSE_EVENT:
  1371. //
  1372. // The channel closed, we need to exit
  1373. //
  1374. //
  1375. // The channel has locked,
  1376. // or the timeout has gone fired and we need to
  1377. // clear the current logon attempt
  1378. // in either case, we need to exit
  1379. //
  1380. done = TRUE;
  1381. //
  1382. // Our attempt to get new data failed
  1383. //
  1384. bSuccess = FALSE;
  1385. break;
  1386. case CHANNEL_LOCK_EVENT:
  1387. //
  1388. // clear the internal lock event
  1389. //
  1390. ResetEvent(m_InternalLockEvent);
  1391. if (m_StartedAuthentication) {
  1392. #if ENABLE_EVENT_DEBUG
  1393. {
  1394. WCHAR blob[256];
  1395. wsprintf(blob,L"ResettingAuthentication\n");
  1396. OutputDebugString(blob);
  1397. }
  1398. #endif
  1399. //
  1400. // the timeout has gone fired and we need to
  1401. // clear the current logon attempt
  1402. //
  1403. done = TRUE;
  1404. //
  1405. // Our attempt to get new data failed
  1406. //
  1407. bSuccess = FALSE;
  1408. }
  1409. break;
  1410. case WAIT_TIMEOUT:
  1411. //
  1412. // we should be in a locked state now
  1413. // which implies we are using the unlocked
  1414. // io handler - the scraper is using the locked one
  1415. //
  1416. ASSERT(myLockedIoHandler == myIoHandler);
  1417. //
  1418. // determine the input buffer status
  1419. //
  1420. bSuccess = myUnlockedIoHandler->HasNewData(&bHasNewData);
  1421. if (! bSuccess) {
  1422. done = TRUE;
  1423. break;
  1424. }
  1425. if (bHasNewData) {
  1426. //
  1427. // We have new data, so we need to exit
  1428. //
  1429. done = TRUE;
  1430. //
  1431. // Consume character the character which caused
  1432. // the waitforuserinput to return
  1433. //
  1434. if (Consume) {
  1435. WCHAR buffer;
  1436. ULONG bufferSize;
  1437. bSuccess = ReadUnlockedIoHandler(
  1438. (PUCHAR)&buffer,
  1439. sizeof(WCHAR),
  1440. &bufferSize
  1441. );
  1442. }
  1443. }
  1444. break;
  1445. default:
  1446. //
  1447. // We should not get here unless something broke
  1448. //
  1449. ASSERT(0);
  1450. bSuccess = FALSE;
  1451. done = TRUE;
  1452. break;
  1453. }
  1454. }
  1455. return bSuccess;
  1456. }