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
1944 lines
42 KiB
/*++
|
|
|
|
Copyright (c) 1999-2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
secio.cpp
|
|
|
|
Abstract:
|
|
|
|
This file contains the implementation of the CSecurityIoHandler
|
|
class which enapsulates the primary security elements used by
|
|
the CSession class.
|
|
|
|
TODO: this class needs to use a TermCap class to abstract the screen
|
|
controls - currently, the class implicitly uses VT-UTF8
|
|
|
|
Author:
|
|
|
|
Brian Guarraci (briangu) 2001.
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <windows.h>
|
|
#include <process.h>
|
|
|
|
#include "cmnhdr.h"
|
|
#include "secio.h"
|
|
#include "nullio.h"
|
|
#include "sacmsg.h"
|
|
#include "utils.h"
|
|
|
|
#define VTUTF8_CLEAR_SCREEN L"\033[2J\033[0;0H"
|
|
|
|
#define READ_BUFFER_LENGTH 512
|
|
#define READ_BUFFER_SIZE (READ_BUFFER_LENGTH * sizeof(WCHAR))
|
|
|
|
CSecurityIoHandler::CSecurityIoHandler(
|
|
IN CIoHandler *LockedIoHandler,
|
|
IN CIoHandler *UnlockedIoHandler
|
|
) : CLockableIoHandler(
|
|
LockedIoHandler,
|
|
UnlockedIoHandler
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Constructor
|
|
|
|
Arguments:
|
|
|
|
LockedIoHandler - the IoHandler to use when the channel is locked
|
|
UnlockedIoHandler - the IoHandler to use when the channel is unlocked
|
|
|
|
Return Value:
|
|
|
|
N/A
|
|
|
|
--*/
|
|
{
|
|
|
|
//
|
|
// Lock the IoHandler so that the read/write routines
|
|
// are disabled.
|
|
//
|
|
Lock();
|
|
|
|
//
|
|
// Validate that our Io Handler pointers are valid
|
|
//
|
|
// This way, we don't have to check everytime we want
|
|
// to use them.
|
|
//
|
|
ASSERT(myLockedIoHandler != NULL);
|
|
ASSERT(myUnlockedIoHandler != NULL);
|
|
ASSERT(myIoHandler != NULL);
|
|
|
|
//
|
|
// initialize our internal lock event
|
|
//
|
|
m_InternalLockEvent = 0;
|
|
|
|
//
|
|
// init
|
|
//
|
|
m_StartedAuthentication = FALSE;
|
|
|
|
|
|
}
|
|
|
|
CSecurityIoHandler::~CSecurityIoHandler()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Desctructor
|
|
|
|
Arguments:
|
|
|
|
N/A
|
|
|
|
Return Value:
|
|
|
|
N/A
|
|
|
|
--*/
|
|
{
|
|
|
|
//
|
|
// Notify the remote user that we are shutting down the
|
|
// command console session
|
|
//
|
|
WriteResourceMessage(SHUTDOWN_NOTICE);
|
|
|
|
//
|
|
// release the redraw handler
|
|
//
|
|
if (m_RedrawHandler) {
|
|
delete m_RedrawHandler;
|
|
}
|
|
|
|
//
|
|
// The CLockableIoHandler destructor deletes the IoHandlers for us.
|
|
//
|
|
NOTHING;
|
|
|
|
//
|
|
// If the TimeOut thread is running, then stop it
|
|
//
|
|
if ((m_TimeOutThreadHandle != INVALID_HANDLE_VALUE) &&
|
|
(m_ThreadExitEvent != NULL)) {
|
|
|
|
//
|
|
// Tell the TimeOut Thread to exit
|
|
//
|
|
SetEvent(m_ThreadExitEvent);
|
|
|
|
//
|
|
// Wait for the thread to exit
|
|
//
|
|
WaitForSingleObject(
|
|
m_TimeOutThreadHandle,
|
|
INFINITE
|
|
);
|
|
|
|
}
|
|
|
|
//
|
|
// Close the internal lock event
|
|
//
|
|
if (m_InternalLockEvent) {
|
|
CloseHandle(m_InternalLockEvent);
|
|
}
|
|
|
|
//
|
|
// Close the thread exit handle
|
|
//
|
|
if (m_ThreadExitEvent != NULL) {
|
|
CloseHandle(m_ThreadExitEvent);
|
|
}
|
|
|
|
//
|
|
// Close the thread handle
|
|
//
|
|
if (m_TimeOutThreadHandle != INVALID_HANDLE_VALUE) {
|
|
CloseHandle(m_TimeOutThreadHandle);
|
|
}
|
|
|
|
}
|
|
|
|
CSecurityIoHandler*
|
|
CSecurityIoHandler::Construct(
|
|
IN SAC_CHANNEL_OPEN_ATTRIBUTES Attributes
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine constructs a security IoHandler connected
|
|
to a channel with the specified attributes.
|
|
|
|
Arguments:
|
|
|
|
Attributes - the attributes of the new channel
|
|
|
|
Return Value:
|
|
|
|
Success - A ptr to a CSecurityIoHandler object.
|
|
Failure - NULL
|
|
|
|
--*/
|
|
{
|
|
BOOL bSuccess;
|
|
CSecurityIoHandler *IoHandler;
|
|
CIoHandler *SacIoHandler;
|
|
CIoHandler *NullIoHandler;
|
|
|
|
//
|
|
// default: failed to construct
|
|
//
|
|
bSuccess = FALSE;
|
|
IoHandler = NULL;
|
|
SacIoHandler = NULL;
|
|
NullIoHandler = NULL;
|
|
|
|
do {
|
|
|
|
BOOL bStatus;
|
|
|
|
//
|
|
// Validate the LockEvent for the timeout thread
|
|
//
|
|
ASSERT(Attributes.LockEvent != NULL);
|
|
if (Attributes.LockEvent == NULL) {
|
|
break;
|
|
}
|
|
|
|
ASSERT(Attributes.LockEvent != INVALID_HANDLE_VALUE);
|
|
if (Attributes.LockEvent == INVALID_HANDLE_VALUE) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Validate the CloseEvent for the WaitForInput thread
|
|
//
|
|
ASSERT(Attributes.CloseEvent != NULL);
|
|
if (Attributes.CloseEvent == NULL) {
|
|
break;
|
|
}
|
|
ASSERT(Attributes.CloseEvent != INVALID_HANDLE_VALUE);
|
|
if (Attributes.CloseEvent == INVALID_HANDLE_VALUE) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Validate the RedrawEvent for the Redraw IoHandler
|
|
//
|
|
ASSERT(Attributes.RedrawEvent != NULL);
|
|
if (Attributes.RedrawEvent == NULL) {
|
|
break;
|
|
}
|
|
ASSERT(Attributes.RedrawEvent != INVALID_HANDLE_VALUE);
|
|
if (Attributes.RedrawEvent == INVALID_HANDLE_VALUE) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Attempt to open a SAC channel
|
|
//
|
|
SacIoHandler = CSacIoHandler::Construct(Attributes);
|
|
|
|
//
|
|
// If we failed to open the SAC channel,
|
|
// then notify the caller that we failed by returning null
|
|
//
|
|
if (SacIoHandler == NULL) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Get the Null Io Handler to be the locked IoHandler
|
|
//
|
|
NullIoHandler = new CNullIoHandler();
|
|
|
|
//
|
|
// Create a new SAC IoHandler
|
|
//
|
|
IoHandler = new CSecurityIoHandler(
|
|
NullIoHandler,
|
|
SacIoHandler
|
|
);
|
|
|
|
//
|
|
// Create the event we will use to signal that a timeout
|
|
// occured while we were trying to authenticate a user
|
|
//
|
|
IoHandler->m_InternalLockEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
|
|
ASSERT(IoHandler->m_InternalLockEvent);
|
|
if (IoHandler->m_InternalLockEvent == 0) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Keep the LockEvent for the timeout thread
|
|
// Keep the CloseEvent for the WaitForInput thread
|
|
//
|
|
IoHandler->m_CloseEvent = Attributes.CloseEvent;
|
|
IoHandler->m_LockEvent = Attributes.LockEvent;
|
|
IoHandler->m_RedrawEvent = Attributes.RedrawEvent;
|
|
|
|
//
|
|
// Create the event used to signal the threads to exit
|
|
//
|
|
IoHandler->m_ThreadExitEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
|
|
if (IoHandler->m_ThreadExitEvent == NULL) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Start the timeout thread if we need to
|
|
//
|
|
bStatus = IoHandler->InitializeTimeOutThread();
|
|
if (! bStatus) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Create handler for redraw events
|
|
//
|
|
IoHandler->m_RedrawHandler = CRedrawHandler::Construct(
|
|
IoHandler,
|
|
Attributes.RedrawEvent
|
|
);
|
|
|
|
ASSERT(IoHandler->m_RedrawHandler);
|
|
if (IoHandler->m_RedrawHandler == NULL) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// we were successful
|
|
//
|
|
bSuccess = TRUE;
|
|
|
|
} while ( FALSE );
|
|
|
|
//
|
|
// if we were not successful
|
|
// then clean up
|
|
//
|
|
if (! bSuccess) {
|
|
|
|
//
|
|
// Note: we do not need to clean up the Lock, Close, and Redraw events
|
|
// because we do not own them. Also, we do not need
|
|
// to clean up the NullIo and SacIo IoHandlers because
|
|
// they are cleaned up by the LockIo parent class.
|
|
//
|
|
|
|
if (IoHandler) {
|
|
delete IoHandler;
|
|
IoHandler = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
return IoHandler;
|
|
}
|
|
|
|
BOOL
|
|
CSecurityIoHandler::Write(
|
|
PBYTE Buffer,
|
|
ULONG BufferSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine implements the IoHandler Write behavior.
|
|
|
|
Arguments:
|
|
|
|
(see iohandler)
|
|
|
|
Return Value:
|
|
|
|
(see iohandler)
|
|
|
|
--*/
|
|
{
|
|
|
|
//
|
|
// Pass through to the secured Io Handler
|
|
//
|
|
return myIoHandler->Write(
|
|
Buffer,
|
|
BufferSize
|
|
);
|
|
|
|
}
|
|
|
|
BOOL
|
|
CSecurityIoHandler::Flush(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine implements the IoHandler Flush behavior.
|
|
|
|
Arguments:
|
|
|
|
(see iohandler)
|
|
|
|
Return Value:
|
|
|
|
(see iohandler)
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Pass through to the secured Io Handler
|
|
//
|
|
return myIoHandler->Flush();
|
|
}
|
|
|
|
BOOL
|
|
CSecurityIoHandler::Read(
|
|
PBYTE Buffer,
|
|
ULONG BufferSize,
|
|
PULONG ByteCount
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine implements the IoHandler Read behavior and
|
|
resets the timeout counter when ever there is a successful
|
|
read.
|
|
|
|
Arguments:
|
|
|
|
(see iohandler)
|
|
|
|
Return Value:
|
|
|
|
(see iohandler)
|
|
|
|
--*/
|
|
{
|
|
BOOL bSuccess;
|
|
|
|
//
|
|
// Pass through to the secured Io Handler
|
|
//
|
|
// if this iohandler is locked,
|
|
// then the caller will be reading from the NullIoHandler
|
|
// else they will read from the UnlockedIoHandler
|
|
//
|
|
bSuccess = myIoHandler->Read(
|
|
Buffer,
|
|
BufferSize,
|
|
ByteCount
|
|
);
|
|
|
|
//
|
|
// If the sesssion received new user input,
|
|
// then reset the timeout counter
|
|
//
|
|
if (*ByteCount > 0) {
|
|
ResetTimeOut();
|
|
}
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
BOOL
|
|
CSecurityIoHandler::ReadUnlockedIoHandler(
|
|
PBYTE Buffer,
|
|
ULONG BufferSize,
|
|
PULONG ByteCount
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine reads a character from the unlocked io hander
|
|
so that we can authenticate the user while the scraper still
|
|
uses the LockedIohandler.
|
|
|
|
resets the timeout counter when ever there is a successful
|
|
read.
|
|
|
|
Arguments:
|
|
|
|
(see iohandler)
|
|
|
|
Return Value:
|
|
|
|
(see iohandler)
|
|
|
|
--*/
|
|
{
|
|
BOOL bSuccess;
|
|
|
|
//
|
|
// Pass through to the secured Io Handler
|
|
//
|
|
bSuccess = myUnlockedIoHandler->Read(
|
|
Buffer,
|
|
BufferSize,
|
|
ByteCount
|
|
);
|
|
|
|
//
|
|
// If the sesssion received new user input,
|
|
// then reset the timeout counter
|
|
//
|
|
if (*ByteCount > 0) {
|
|
ResetTimeOut();
|
|
}
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
BOOL
|
|
CSecurityIoHandler::HasNewData(
|
|
PBOOL InputWaiting
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine implements the IoHandler HasNewData behavior.
|
|
|
|
Arguments:
|
|
|
|
(see iohandler)
|
|
|
|
Return Value:
|
|
|
|
(see iohandler)
|
|
|
|
|
|
--*/
|
|
{
|
|
|
|
//
|
|
// Pass through to the secured Io Handler
|
|
//
|
|
return myIoHandler->HasNewData(InputWaiting);
|
|
|
|
}
|
|
|
|
BOOL
|
|
CSecurityIoHandler::WriteResourceMessage(
|
|
IN INT MsgId
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine writes a resource string message to
|
|
the Unlocked ioHandler.
|
|
|
|
Arguments:
|
|
|
|
MsgId - the id of the message to write
|
|
|
|
Return Value:
|
|
|
|
TRUE - the message was loaded and written
|
|
FALSE - failed
|
|
|
|
--*/
|
|
{
|
|
UNICODE_STRING UnicodeString = {0};
|
|
BOOL bSuccess;
|
|
|
|
//
|
|
// Default: failed
|
|
//
|
|
bSuccess = FALSE;
|
|
|
|
//
|
|
// Attempt to load the string and write it
|
|
//
|
|
do {
|
|
|
|
if ( LoadStringResource(&UnicodeString, MsgId) ) {
|
|
|
|
//
|
|
// Terminate the string at the %0 marker, if it is present
|
|
//
|
|
if( wcsstr( UnicodeString.Buffer, L"%0" ) ) {
|
|
*((PWCHAR)wcsstr( UnicodeString.Buffer, L"%0" )) = L'\0';
|
|
}
|
|
|
|
//
|
|
// Write the message
|
|
//
|
|
bSuccess = m_RedrawHandler->Write(
|
|
(PUCHAR)UnicodeString.Buffer,
|
|
(ULONG)(wcslen( UnicodeString.Buffer) * sizeof(WCHAR))
|
|
);
|
|
|
|
if (!bSuccess) {
|
|
break;
|
|
}
|
|
|
|
bSuccess = m_RedrawHandler->Flush();
|
|
|
|
}
|
|
|
|
} while ( FALSE );
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
BOOL
|
|
CSecurityIoHandler::LoadStringResource(
|
|
IN PUNICODE_STRING pUnicodeString,
|
|
IN INT MsgId
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is a simple implementation of LoadString().
|
|
|
|
Arguments:
|
|
|
|
usString - Returns the resource string.
|
|
MsgId - Supplies the message id of the resource string.
|
|
|
|
Return Value:
|
|
|
|
FALSE - Failure.
|
|
TRUE - Success.
|
|
|
|
--*/
|
|
{
|
|
|
|
NTSTATUS Status;
|
|
PMESSAGE_RESOURCE_ENTRY MessageEntry;
|
|
ANSI_STRING AnsiString;
|
|
|
|
Status = RtlFindMessage( NtCurrentPeb()->ImageBaseAddress,
|
|
(ULONG_PTR) RT_MESSAGETABLE,
|
|
0,
|
|
(ULONG)MsgId,
|
|
&MessageEntry
|
|
);
|
|
|
|
if (!NT_SUCCESS( Status )) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (!(MessageEntry->Flags & MESSAGE_RESOURCE_UNICODE)) {
|
|
RtlInitAnsiString( &AnsiString, (PCSZ)&MessageEntry->Text[ 0 ] );
|
|
Status = RtlAnsiStringToUnicodeString( pUnicodeString, &AnsiString, TRUE );
|
|
if (!NT_SUCCESS( Status )) {
|
|
return FALSE;
|
|
}
|
|
} else {
|
|
RtlCreateUnicodeString(pUnicodeString, (PWSTR)MessageEntry->Text);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
CSecurityIoHandler::AuthenticateCredentials(
|
|
IN PWSTR UserName,
|
|
IN PWSTR DomainName,
|
|
IN PWSTR Password,
|
|
OUT PHANDLE pUserToken
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will attempt to authenticate the supplied credentials.
|
|
|
|
Arguments:
|
|
|
|
UserName - Supplied UserName
|
|
|
|
DomainName - Supplied DomainName
|
|
|
|
Password - Supplied Password
|
|
|
|
pUserToken - Holds the valid token for the authenticated user
|
|
credentials.
|
|
|
|
Return Value:
|
|
|
|
TRUE - Credentials successfully authenticated.
|
|
FALSE - Credentials failed to authenticate.
|
|
|
|
Security:
|
|
|
|
interface: exposes user input to LogonUser()
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOL b;
|
|
|
|
//
|
|
// Notify the user that we are attempting to authenticate
|
|
//
|
|
WriteResourceMessage(LOGIN_IN_PROGRESS);
|
|
|
|
//
|
|
// Try the authentication.
|
|
//
|
|
b = LogonUser( UserName,
|
|
DomainName,
|
|
Password,
|
|
LOGON32_LOGON_INTERACTIVE,
|
|
LOGON32_PROVIDER_DEFAULT,
|
|
pUserToken );
|
|
|
|
if (b) {
|
|
|
|
//
|
|
// Reset the timeout counter before we start the thread
|
|
//
|
|
ResetTimeOut();
|
|
|
|
} else {
|
|
|
|
//
|
|
// Wait 3 seconds before returning control to user in
|
|
// order to slow iterative attacks
|
|
//
|
|
Sleep(3000);
|
|
|
|
//
|
|
// Notify the user that the attempt failed
|
|
//
|
|
WriteResourceMessage(LOGIN_FAILURE);
|
|
|
|
//
|
|
// Wait for a key press
|
|
//
|
|
WaitForUserInput(TRUE);
|
|
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
BOOL
|
|
CSecurityIoHandler::RetrieveCredential(
|
|
OUT PWSTR String,
|
|
IN ULONG StringLength,
|
|
IN BOOL EchoClearText
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will request credentials from the user. Those
|
|
credentials are then returned to the caller.
|
|
|
|
Arguments:
|
|
|
|
String - on success, contains the credential
|
|
StringLength - the # of WCHARS (length) in the string (includes NULL termination)
|
|
EchoClearText - TRUE: echo user input in clear text
|
|
FALSE: echo user input as '*'
|
|
|
|
Return Value:
|
|
|
|
TRUE - Credential recieved.
|
|
FALSE - Something failed when we were trying to get credentials
|
|
from the user.
|
|
|
|
Security:
|
|
|
|
interface: external input
|
|
echos user input
|
|
|
|
--*/
|
|
{
|
|
PWCHAR buffer;
|
|
ULONG bufferSize;
|
|
ULONG i, j;
|
|
BOOLEAN Done = FALSE;
|
|
BOOL bSuccess;
|
|
|
|
//
|
|
// validate parameters
|
|
//
|
|
if (! String) {
|
|
return FALSE;
|
|
}
|
|
if (StringLength < 1) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// default: failed
|
|
//
|
|
bSuccess = FALSE;
|
|
|
|
//
|
|
// allocate the buffer we'll use to read the channel
|
|
//
|
|
buffer = new WCHAR[READ_BUFFER_LENGTH];
|
|
|
|
//
|
|
// default: start at the first character
|
|
//
|
|
i = 0;
|
|
|
|
//
|
|
// default: we need to read user input
|
|
//
|
|
Done = FALSE;
|
|
|
|
//
|
|
// Attempt to retrieve the credential
|
|
//
|
|
while ( !Done ) {
|
|
|
|
//
|
|
// Wait until the user inputs something
|
|
//
|
|
bSuccess = WaitForUserInput(FALSE);
|
|
|
|
if (!bSuccess) {
|
|
Done = TRUE;
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Read what the user input
|
|
//
|
|
|
|
//
|
|
// we should be in a locked state now
|
|
// which implies we are using the unlocked
|
|
// io handler - the scraper is using the locked one
|
|
//
|
|
ASSERT(myLockedIoHandler == myIoHandler);
|
|
|
|
bSuccess = ReadUnlockedIoHandler(
|
|
(PUCHAR)buffer,
|
|
READ_BUFFER_SIZE,
|
|
&bufferSize
|
|
);
|
|
|
|
if (bSuccess) {
|
|
|
|
//
|
|
// We have received at least one character
|
|
// hence by setting this to true, we enable
|
|
// the internal lock event to succeed in
|
|
// resetting the authentication attempt
|
|
// that is, if the user starts to authenticate
|
|
// and stops before finishing, the timer will
|
|
// fire and reset the authentication attempt
|
|
//
|
|
m_StartedAuthentication = TRUE;
|
|
|
|
//
|
|
// Process the characters he gave us.
|
|
//
|
|
// Note: the buffer contains WCHARs, hence we need to
|
|
// divide the returned buffersize by sizeof(WCHAR) in
|
|
// order to get the # of wchars to process.
|
|
//
|
|
for ( j = 0; j < bufferSize/sizeof(WCHAR); j++ ) {
|
|
|
|
//
|
|
// stop if:
|
|
//
|
|
// we reached the end of the Credentials buffer (not including the NULL)
|
|
// we received a CR || LF
|
|
//
|
|
if ( (i >= (StringLength-1)) || (buffer[j] == 0x0D) || (buffer[j] == 0x0A) ) {
|
|
Done = TRUE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// handle user input
|
|
//
|
|
if( buffer[j] == '\b' ) {
|
|
|
|
//
|
|
// The user gave us a backspace. We should cover up the
|
|
// character on the screen, then backup our index so we
|
|
// essentially forget the last thing he gave us.
|
|
//
|
|
// If the very first thing the user did was type in a backspace,
|
|
// no need to back anything up.
|
|
//
|
|
if( i > 0 ) {
|
|
|
|
i--;
|
|
|
|
String[i] = L'\0';
|
|
|
|
bSuccess = m_RedrawHandler->Write(
|
|
(PUCHAR)L"\b \b",
|
|
(ULONG)(wcslen(L"\b \b") * sizeof(WCHAR))
|
|
);
|
|
|
|
if (!bSuccess) {
|
|
|
|
//
|
|
// write failed: exit
|
|
//
|
|
|
|
Done = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (buffer[j] < ' ') {
|
|
|
|
//
|
|
// If the character is less than ' ' (a control char),
|
|
// then ignore it
|
|
//
|
|
NOTHING;
|
|
|
|
} else {
|
|
|
|
//
|
|
// It was a valid character: remember the input and echo it back
|
|
// to the user.
|
|
//
|
|
|
|
String[i] = buffer[j];
|
|
|
|
i++;
|
|
|
|
//
|
|
// Echo according to caller specifications
|
|
//
|
|
bSuccess = m_RedrawHandler->Write(
|
|
EchoClearText ? (PUCHAR)&buffer[j] : (PUCHAR)L"*",
|
|
sizeof(WCHAR)
|
|
);
|
|
|
|
if (!bSuccess) {
|
|
|
|
//
|
|
// write failed: exit
|
|
//
|
|
|
|
Done = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (bSuccess) {
|
|
|
|
//
|
|
// Flush any text echoing we've done.
|
|
//
|
|
bSuccess = m_RedrawHandler->Flush();
|
|
|
|
if (!bSuccess) {
|
|
|
|
//
|
|
// write failed: exit
|
|
//
|
|
|
|
Done = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// read failed: exit
|
|
//
|
|
Done = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Terminate the credential
|
|
//
|
|
String[i] = UNICODE_NULL;
|
|
|
|
//
|
|
// release the read buffer
|
|
//
|
|
delete [] buffer;
|
|
|
|
return bSuccess;
|
|
|
|
}
|
|
|
|
BOOL
|
|
CSecurityIoHandler::RetrieveCredentials(
|
|
IN OUT PWSTR UserName,
|
|
IN ULONG UserNameLength,
|
|
IN OUT PWSTR DomainName,
|
|
IN ULONG DomainNameLength,
|
|
IN OUT PWSTR Password,
|
|
IN ULONG PasswordLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will request credentials from the user. Those
|
|
credentials are then returned to the caller.
|
|
|
|
Arguments:
|
|
|
|
UserName - Buffer to hold the UserName
|
|
UserNameLength - Length of the UserName buffer
|
|
|
|
DomainName - Buffer to hold the DomainName
|
|
DomainNameLength - Length of the DomainName buffer
|
|
|
|
Password - Buffer to hold the Password
|
|
PasswordLength - Length of the Password buffer
|
|
|
|
Return Value:
|
|
|
|
TRUE - Credentials recieved.
|
|
FALSE - Something failed when we were trying to get credentials
|
|
from the user.
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOL HaveDomainName;
|
|
BOOL bSuccess;
|
|
|
|
//
|
|
// Initialize the flag that we use to keep track
|
|
// of when the user first starts to authenticate.
|
|
// that is, after they enter at least one character
|
|
// they have started to authenticate.
|
|
//
|
|
m_StartedAuthentication = FALSE;
|
|
|
|
//
|
|
// Initialize our redraw screen
|
|
//
|
|
m_RedrawHandler->Reset();
|
|
|
|
//
|
|
// Clear the screen
|
|
//
|
|
m_RedrawHandler->Write(
|
|
(PUCHAR)VTUTF8_CLEAR_SCREEN,
|
|
(ULONG)(wcslen( VTUTF8_CLEAR_SCREEN ) * sizeof(WCHAR))
|
|
);
|
|
m_RedrawHandler->Flush();
|
|
|
|
//
|
|
// Put up the login banner.
|
|
//
|
|
if (! WriteResourceMessage(LOGIN_BANNER) ) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Prompt for user name.
|
|
//
|
|
if (! WriteResourceMessage(USERNAME_PROMPT) ) {
|
|
return FALSE;
|
|
}
|
|
|
|
if ( UserName[0] != UNICODE_NULL ) {
|
|
|
|
//
|
|
// We were supplied a UserName. Put that up and proceed.
|
|
//
|
|
m_RedrawHandler->Write(
|
|
(PUCHAR)UserName,
|
|
(ULONG)(wcslen( UserName ) * sizeof(WCHAR))
|
|
);
|
|
m_RedrawHandler->Flush();
|
|
|
|
//
|
|
// If we were given the username, we conclude that
|
|
// they gave us the domain name as well. We need
|
|
// to do this since the domain name may be empty
|
|
// and we automatlically conclude that because the
|
|
// domain name is empty we need to retrieve it.
|
|
//
|
|
HaveDomainName = TRUE;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Retrieve the UserName.
|
|
//
|
|
bSuccess = RetrieveCredential(
|
|
UserName,
|
|
UserNameLength,
|
|
TRUE
|
|
);
|
|
|
|
if (!bSuccess) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// We need to retrieve the domain name too.
|
|
//
|
|
HaveDomainName = FALSE;
|
|
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
m_RedrawHandler->Write(
|
|
(PUCHAR)L"\r\n",
|
|
(ULONG)(wcslen(L"\r\n") * sizeof(WCHAR))
|
|
);
|
|
m_RedrawHandler->Flush();
|
|
|
|
//
|
|
// Prompt for domain name
|
|
//
|
|
if (! WriteResourceMessage(DOMAINNAME_PROMPT) ) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Prompt for domain name.
|
|
//
|
|
if ( HaveDomainName ) {
|
|
|
|
//
|
|
// We were supplied a username. Put that up and proceed.
|
|
//
|
|
m_RedrawHandler->Write(
|
|
(PUCHAR)DomainName,
|
|
(ULONG)(wcslen( DomainName ) * sizeof(WCHAR))
|
|
);
|
|
m_RedrawHandler->Flush();
|
|
|
|
} else {
|
|
|
|
//
|
|
// Retrieve the DomainName.
|
|
//
|
|
bSuccess = RetrieveCredential(
|
|
DomainName,
|
|
DomainNameLength,
|
|
TRUE
|
|
);
|
|
|
|
if (!bSuccess) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// If user entered a blank domain, force it to '.'
|
|
// which implies local machine domain
|
|
//
|
|
if (wcslen(DomainName) == 0) {
|
|
wsprintf(
|
|
DomainName,
|
|
L"."
|
|
);
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
m_RedrawHandler->Write(
|
|
(PUCHAR)L"\r\n",
|
|
(ULONG)(wcslen(L"\r\n") * sizeof(WCHAR))
|
|
);
|
|
|
|
//
|
|
// Prompt for password.
|
|
//
|
|
if (! WriteResourceMessage(PASSWORD_PROMPT) ) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Retrieve the Password.
|
|
//
|
|
bSuccess = RetrieveCredential(
|
|
Password,
|
|
PasswordLength,
|
|
FALSE
|
|
);
|
|
|
|
if (!bSuccess) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
m_RedrawHandler->Write(
|
|
(PUCHAR)L"\r\n",
|
|
(ULONG)(wcslen(L"\r\n") * sizeof(WCHAR))
|
|
);
|
|
m_RedrawHandler->Flush();
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
VOID
|
|
CSecurityIoHandler::ResetTimeOut(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine resets the StartTickCount to 0
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
ULONG TimerTick;
|
|
|
|
//
|
|
// Get the current timer tick
|
|
//
|
|
TimerTick = GetTickCount();
|
|
|
|
//
|
|
// Reset the timeout counter by making the current timer tick
|
|
// the starting tick count
|
|
//
|
|
InterlockedExchange(&m_StartTickCount, TimerTick);
|
|
|
|
#if ENABLE_EVENT_DEBUG
|
|
{
|
|
WCHAR blob[256];
|
|
wsprintf(blob,L"ResetTimeOut\n");
|
|
OutputDebugString(blob);
|
|
}
|
|
#endif
|
|
|
|
}
|
|
|
|
BOOL
|
|
CSecurityIoHandler::TimeOutOccured(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine determines if the specified timeout interval
|
|
has been reached. It takes the specified TickCount and
|
|
compares it to the m_StartTickCount. If the interval equals
|
|
or exceeds the timeout interval, then a timeout has occured.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
TRUE - The timeout interval has been reached
|
|
FALSE - otherwise
|
|
|
|
--*/
|
|
{
|
|
BOOL bTimedOut;
|
|
DWORD DeltaT;
|
|
|
|
//
|
|
// default: we did not time out
|
|
//
|
|
bTimedOut = FALSE;
|
|
|
|
//
|
|
// See if we timed out
|
|
//
|
|
DeltaT = GetAndComputeTickCountDeltaT(m_StartTickCount);
|
|
|
|
if (DeltaT >= m_TimeOutInterval) {
|
|
|
|
//
|
|
// Reset the timeout counter
|
|
//
|
|
ResetTimeOut();
|
|
|
|
//
|
|
// We timed out
|
|
//
|
|
bTimedOut = TRUE;
|
|
|
|
#if ENABLE_EVENT_DEBUG
|
|
{
|
|
WCHAR blob[256];
|
|
wsprintf(blob,L"TimeOutOccured\n");
|
|
OutputDebugString(blob);
|
|
}
|
|
#endif
|
|
|
|
}
|
|
|
|
return bTimedOut;
|
|
|
|
}
|
|
|
|
BOOL
|
|
CSecurityIoHandler::InitializeTimeOutThread(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine initializes the timeout thread if timeout
|
|
behavior is enabled.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
TRUE Success
|
|
FALSE Otherwise
|
|
|
|
--*/
|
|
{
|
|
BOOL bSuccess;
|
|
|
|
//
|
|
// default: failed to init
|
|
//
|
|
bSuccess = FALSE;
|
|
|
|
//
|
|
// default: we do not have a timeout thread
|
|
//
|
|
m_TimeOutThreadHandle = INVALID_HANDLE_VALUE;
|
|
|
|
//
|
|
// determine if we need a timeout thread
|
|
// if we do, then set one up
|
|
//
|
|
do {
|
|
|
|
//
|
|
// If the timeout behavior is disabled,
|
|
// then we are done.
|
|
//
|
|
if (IsTimeOutEnabled() == FALSE) {
|
|
|
|
//
|
|
// No Initialization required
|
|
//
|
|
bSuccess = TRUE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
//
|
|
// determine the time out interval
|
|
//
|
|
if (GetTimeOutInterval(&m_TimeOutInterval) == TRUE) {
|
|
|
|
//
|
|
// Reset the timeout counter before we start the thread
|
|
//
|
|
ResetTimeOut();
|
|
|
|
//
|
|
// Create thread to handle Input
|
|
//
|
|
m_TimeOutThreadHandle = (HANDLE)_beginthreadex(
|
|
NULL,
|
|
0,
|
|
CSecurityIoHandler::TimeOutThread,
|
|
this,
|
|
0,
|
|
(unsigned int*)&m_TimeOutThreadTID
|
|
);
|
|
|
|
if (m_TimeOutThreadHandle == INVALID_HANDLE_VALUE) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// we successfully started the thread
|
|
//
|
|
bSuccess = TRUE;
|
|
|
|
}
|
|
|
|
} while ( FALSE );
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
BOOL
|
|
CSecurityIoHandler::GetTimeOutInterval(
|
|
OUT PULONG TimeOutDuration
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine determines the timeout interval.
|
|
|
|
It attempts to read the registry and use a specified
|
|
value from there, or defaults.
|
|
|
|
Arguments:
|
|
|
|
TimeOutDuration - the determined timeout interval
|
|
|
|
Return Value:
|
|
|
|
TRUE - TimeOutDuration is valid
|
|
FALSE - otherwise
|
|
|
|
Security:
|
|
|
|
interface: registry
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD rc;
|
|
HKEY hKey;
|
|
DWORD DWord;
|
|
DWORD dwsize;
|
|
DWORD DataType;
|
|
|
|
//
|
|
// See if the user gave us a registry key to define the timeout duration
|
|
//
|
|
rc = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
|
SACSVR_PARAMETERS_KEY,
|
|
0,
|
|
KEY_READ,
|
|
&hKey );
|
|
|
|
if( rc == NO_ERROR ) {
|
|
|
|
dwsize = sizeof(DWORD);
|
|
|
|
rc = RegQueryValueEx(
|
|
hKey,
|
|
SACSVR_TIMEOUT_INTERVAL_VALUE,
|
|
NULL,
|
|
&DataType,
|
|
(LPBYTE)&DWord,
|
|
&dwsize );
|
|
|
|
RegCloseKey( hKey );
|
|
|
|
if ((rc == NO_ERROR) &&
|
|
(DataType == REG_DWORD) &&
|
|
(dwsize == sizeof(DWORD))
|
|
) {
|
|
|
|
//
|
|
// Convert the specified timeout from minutes --> ms
|
|
//
|
|
*TimeOutDuration = DWord * (60 * 1000);
|
|
|
|
//
|
|
// A timeout interval of 0 is not allowed, default.
|
|
//
|
|
if (*TimeOutDuration == 0) {
|
|
|
|
*TimeOutDuration = DEFAULT_TIME_OUT_INTERVAL;
|
|
|
|
}
|
|
|
|
//
|
|
// clamp the timeout interval to a reasonable value
|
|
//
|
|
if (*TimeOutDuration > MAX_TIME_OUT_INTERVAL) {
|
|
|
|
*TimeOutDuration = MAX_TIME_OUT_INTERVAL;
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Default: timeout duration
|
|
//
|
|
*TimeOutDuration = DEFAULT_TIME_OUT_INTERVAL;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
BOOL
|
|
CSecurityIoHandler::IsTimeOutEnabled(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine determines if the timeout behavior is enabled
|
|
by the system.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
TRUE - timeout behavior is enabled
|
|
FALSE - otherwise
|
|
|
|
Security:
|
|
|
|
interface: registry
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD rc;
|
|
HKEY hKey;
|
|
DWORD DWord;
|
|
DWORD dwsize;
|
|
DWORD DataType;
|
|
|
|
//
|
|
// See if the user gave us a registry key to disable the timeout behavior
|
|
//
|
|
rc = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
|
SACSVR_PARAMETERS_KEY,
|
|
0,
|
|
KEY_READ,
|
|
&hKey );
|
|
|
|
if( rc == NO_ERROR ) {
|
|
|
|
dwsize = sizeof(DWORD);
|
|
|
|
rc = RegQueryValueEx(
|
|
hKey,
|
|
SACSVR_TIMEOUT_DISABLED_VALUE,
|
|
NULL,
|
|
&DataType,
|
|
(LPBYTE)&DWord,
|
|
&dwsize );
|
|
|
|
RegCloseKey( hKey );
|
|
|
|
if ((rc == NO_ERROR) &&
|
|
(DataType == REG_DWORD) &&
|
|
(dwsize == sizeof(DWORD))
|
|
) {
|
|
|
|
return DWord == 1 ? FALSE : TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// default: timeout is enabled
|
|
//
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
unsigned int
|
|
CSecurityIoHandler::TimeOutThread(
|
|
PVOID pParam
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is a the timeout management thread.
|
|
|
|
When the Timeout interval is reached, this routine
|
|
fires the lock event and causes the session to perform
|
|
its locking behavior.
|
|
|
|
Arguments:
|
|
|
|
pParam - thread context
|
|
|
|
Return Value:
|
|
|
|
thread return value
|
|
|
|
--*/
|
|
{
|
|
CSecurityIoHandler *IoHandler;
|
|
BOOL bContinueSession;
|
|
DWORD dwRetVal;
|
|
DWORD dwPollInterval;
|
|
HANDLE handles[2];
|
|
ULONG HandleCount;
|
|
BOOL bRedrawEventSignaled;
|
|
|
|
enum {
|
|
CHANNEL_THREAD_EXIT_EVENT = WAIT_OBJECT_0,
|
|
CHANNEL_REDRAW_EVENT
|
|
};
|
|
|
|
//
|
|
// Get the session object
|
|
//
|
|
IoHandler = (CSecurityIoHandler*)pParam;
|
|
|
|
//
|
|
// Assign the events to listen for
|
|
//
|
|
handles[0] = IoHandler->m_ThreadExitEvent;
|
|
handles[1] = IoHandler->m_RedrawEvent;
|
|
|
|
//
|
|
// default: listen
|
|
//
|
|
bContinueSession = TRUE;
|
|
|
|
//
|
|
// wait on the redraw event
|
|
//
|
|
bRedrawEventSignaled = FALSE;
|
|
|
|
//
|
|
// Poll Interval = 1 second
|
|
//
|
|
dwPollInterval = 1000;
|
|
|
|
//
|
|
// While we should listen...
|
|
//
|
|
while ( bContinueSession ) {
|
|
|
|
HandleCount = bRedrawEventSignaled ? 1 : 2;
|
|
|
|
//
|
|
// Wait for our exit event
|
|
//
|
|
dwRetVal = WaitForMultipleObjects(
|
|
HandleCount,
|
|
handles,
|
|
FALSE,
|
|
dwPollInterval
|
|
);
|
|
|
|
switch ( dwRetVal ) {
|
|
|
|
case CHANNEL_REDRAW_EVENT:
|
|
|
|
//
|
|
// reset the timeout if someone switches back to a channel
|
|
//
|
|
IoHandler->ResetTimeOut();
|
|
|
|
//
|
|
// We don't need to waint on this event again until it clears
|
|
//
|
|
bRedrawEventSignaled = TRUE;
|
|
|
|
break;
|
|
|
|
case WAIT_TIMEOUT: {
|
|
|
|
//
|
|
// Check for timeout
|
|
//
|
|
if (IoHandler->TimeOutOccured()) {
|
|
|
|
//
|
|
// set the lock event causing
|
|
// the command console session to lock.
|
|
//
|
|
SetEvent(IoHandler->m_LockEvent);
|
|
|
|
//
|
|
// Set the internal lock event
|
|
//
|
|
SetEvent(IoHandler->m_InternalLockEvent);
|
|
|
|
}
|
|
|
|
//
|
|
// Wait until the event clears by looking
|
|
// for a WAIT_TIMEOUT
|
|
//
|
|
dwRetVal = WaitForSingleObject(
|
|
IoHandler->m_RedrawEvent,
|
|
0
|
|
);
|
|
|
|
//
|
|
// Check the wait result
|
|
//
|
|
switch (dwRetVal) {
|
|
case WAIT_TIMEOUT:
|
|
|
|
//
|
|
// It's ok to wait for this event again
|
|
//
|
|
bRedrawEventSignaled = FALSE;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ASSERT (dwRetVal != WAIT_FAILED);
|
|
if (dwRetVal == WAIT_FAILED) {
|
|
bContinueSession = false;
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case CHANNEL_THREAD_EXIT_EVENT:
|
|
default:
|
|
|
|
//
|
|
// incase WAIT_FAILED, call GetLastError()
|
|
//
|
|
ASSERT(dwRetVal != WAIT_FAILED);
|
|
|
|
//
|
|
// An error has occured, stop listening
|
|
//
|
|
bContinueSession = FALSE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
BOOL
|
|
CSecurityIoHandler::WaitForUserInput(
|
|
IN BOOL Consume
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine blocks waiting for user input.
|
|
|
|
Arguments:
|
|
|
|
Consume - if TRUE, this routine eats the character that caused
|
|
the the channel to have new data.
|
|
|
|
Return Value:
|
|
|
|
TRUE - no errors
|
|
FALSE - otherwise
|
|
|
|
--*/
|
|
{
|
|
BOOL bSuccess;
|
|
DWORD dwRetVal;
|
|
BOOL bHasNewData;
|
|
BOOL done;
|
|
HANDLE handles[2];
|
|
|
|
enum {
|
|
CHANNEL_CLOSE_EVENT = WAIT_OBJECT_0,
|
|
CHANNEL_LOCK_EVENT
|
|
};
|
|
|
|
//
|
|
// Assign the events to listen for
|
|
//
|
|
handles[0] = m_CloseEvent;
|
|
handles[1] = m_InternalLockEvent;
|
|
|
|
//
|
|
// Default: we succeeded
|
|
//
|
|
bSuccess = TRUE;
|
|
|
|
//
|
|
// Default: we loop
|
|
//
|
|
done = FALSE;
|
|
|
|
//
|
|
// Wait for a key press
|
|
//
|
|
while (!done) {
|
|
|
|
dwRetVal = WaitForMultipleObjects(
|
|
sizeof(handles) / sizeof(handles[0]),
|
|
handles,
|
|
FALSE,
|
|
20 // 20ms
|
|
);
|
|
|
|
switch(dwRetVal) {
|
|
case CHANNEL_CLOSE_EVENT:
|
|
|
|
//
|
|
// The channel closed, we need to exit
|
|
//
|
|
//
|
|
// The channel has locked,
|
|
// or the timeout has gone fired and we need to
|
|
// clear the current logon attempt
|
|
// in either case, we need to exit
|
|
//
|
|
done = TRUE;
|
|
|
|
//
|
|
// Our attempt to get new data failed
|
|
//
|
|
bSuccess = FALSE;
|
|
|
|
break;
|
|
|
|
case CHANNEL_LOCK_EVENT:
|
|
|
|
//
|
|
// clear the internal lock event
|
|
//
|
|
ResetEvent(m_InternalLockEvent);
|
|
|
|
if (m_StartedAuthentication) {
|
|
|
|
#if ENABLE_EVENT_DEBUG
|
|
{
|
|
WCHAR blob[256];
|
|
wsprintf(blob,L"ResettingAuthentication\n");
|
|
OutputDebugString(blob);
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// the timeout has gone fired and we need to
|
|
// clear the current logon attempt
|
|
//
|
|
done = TRUE;
|
|
|
|
//
|
|
// Our attempt to get new data failed
|
|
//
|
|
bSuccess = FALSE;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case WAIT_TIMEOUT:
|
|
|
|
//
|
|
// we should be in a locked state now
|
|
// which implies we are using the unlocked
|
|
// io handler - the scraper is using the locked one
|
|
//
|
|
ASSERT(myLockedIoHandler == myIoHandler);
|
|
|
|
//
|
|
// determine the input buffer status
|
|
//
|
|
bSuccess = myUnlockedIoHandler->HasNewData(&bHasNewData);
|
|
|
|
if (! bSuccess) {
|
|
done = TRUE;
|
|
break;
|
|
}
|
|
|
|
if (bHasNewData) {
|
|
|
|
//
|
|
// We have new data, so we need to exit
|
|
//
|
|
done = TRUE;
|
|
|
|
//
|
|
// Consume character the character which caused
|
|
// the waitforuserinput to return
|
|
//
|
|
if (Consume) {
|
|
|
|
WCHAR buffer;
|
|
ULONG bufferSize;
|
|
|
|
bSuccess = ReadUnlockedIoHandler(
|
|
(PUCHAR)&buffer,
|
|
sizeof(WCHAR),
|
|
&bufferSize
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
//
|
|
// We should not get here unless something broke
|
|
//
|
|
ASSERT(0);
|
|
|
|
bSuccess = FALSE;
|
|
done = TRUE;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
return bSuccess;
|
|
}
|
|
|