1061 lines
35 KiB
C++
1061 lines
35 KiB
C++
|
// --------------------------------------------------------------------------
|
||
|
// Module Name: CInteractiveLogon.cpp
|
||
|
//
|
||
|
// Copyright (c) 2000, Microsoft Corporation
|
||
|
//
|
||
|
// File that implements encapsulation of interactive logon information.
|
||
|
//
|
||
|
// History: 2000-12-07 vtan created
|
||
|
// --------------------------------------------------------------------------
|
||
|
|
||
|
#include "priv.h"
|
||
|
#include "CInteractiveLogon.h"
|
||
|
|
||
|
#include <winsta.h>
|
||
|
|
||
|
#include "GinaIPC.h"
|
||
|
#include "TokenInformation.h"
|
||
|
#include "UIHostIPC.h"
|
||
|
|
||
|
const TCHAR CInteractiveLogon::s_szEventReplyName[] = TEXT("shgina: InteractiveLogonRequestReply");
|
||
|
const TCHAR CInteractiveLogon::s_szEventSignalName[] = TEXT("shgina: InteractiveLogonRequestSignal");
|
||
|
const TCHAR CInteractiveLogon::s_szSectionName[] = TEXT("shgina: InteractiveLogonRequestSection");
|
||
|
|
||
|
// --------------------------------------------------------------------------
|
||
|
// CInteractiveLogon::CRequestData::CRequestData
|
||
|
//
|
||
|
// Arguments: <none>
|
||
|
//
|
||
|
// Returns: <none>
|
||
|
//
|
||
|
// Purpose: Constructor for CRequestData.
|
||
|
//
|
||
|
// History: 2000-12-08 vtan created
|
||
|
// --------------------------------------------------------------------------
|
||
|
|
||
|
CInteractiveLogon::CRequestData::CRequestData (void)
|
||
|
|
||
|
{
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------------------------------------
|
||
|
// CInteractiveLogon::CRequestData::~CRequestData
|
||
|
//
|
||
|
// Arguments: <none>
|
||
|
//
|
||
|
// Returns: <none>
|
||
|
//
|
||
|
// Purpose: Destructor for CRequestData.
|
||
|
//
|
||
|
// History: 2000-12-08 vtan created
|
||
|
// --------------------------------------------------------------------------
|
||
|
|
||
|
CInteractiveLogon::CRequestData::~CRequestData (void)
|
||
|
|
||
|
{
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------------------------------------
|
||
|
// CInteractiveLogon::CRequestData::Set
|
||
|
//
|
||
|
// Arguments: pszUsername = Username.
|
||
|
// pszDomain = Domain.
|
||
|
// pszPassword = Password.
|
||
|
//
|
||
|
// Returns: <none>
|
||
|
//
|
||
|
// Purpose: Sets the information into the section object. Makes the data
|
||
|
// valid by signing it with a 4-byte signature.
|
||
|
//
|
||
|
// History: 2000-12-07 vtan created
|
||
|
// --------------------------------------------------------------------------
|
||
|
|
||
|
void CInteractiveLogon::CRequestData::Set (const WCHAR *pszUsername, const WCHAR *pszDomain, WCHAR *pszPassword)
|
||
|
|
||
|
{
|
||
|
UNICODE_STRING passwordString;
|
||
|
|
||
|
_ulMagicNumber = MAGIC_NUMBER;
|
||
|
_dwErrorCode = ERROR_ACCESS_DENIED;
|
||
|
lstrcpyn(_szEventReplyName, s_szEventReplyName, ARRAYSIZE(s_szEventReplyName));
|
||
|
lstrcpyn(_szUsername, pszUsername, ARRAYSIZE(_szUsername));
|
||
|
lstrcpyn(_szDomain, pszDomain, ARRAYSIZE(_szDomain));
|
||
|
lstrcpyn(_szPassword, pszPassword, ARRAYSIZE(_szPassword));
|
||
|
ZeroMemory(pszPassword, (lstrlen(pszPassword) + sizeof('\0')) * sizeof(WCHAR));
|
||
|
_iPasswordLength = lstrlen(_szPassword);
|
||
|
if (_iPasswordLength > 127)
|
||
|
{
|
||
|
_iPasswordLength = 127;
|
||
|
}
|
||
|
_szPassword[_iPasswordLength] = L'\0';
|
||
|
RtlInitUnicodeString(&passwordString, _szPassword);
|
||
|
_ucSeed = 0;
|
||
|
RtlRunEncodeUnicodeString(&_ucSeed, &passwordString);
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------------------------------------
|
||
|
// CInteractiveLogon::CRequestData::Get
|
||
|
//
|
||
|
// Arguments: pszUsername = Username (returned).
|
||
|
// pszDomain = Domain (returned).
|
||
|
// pszPassword = Password (clear-text) returned.
|
||
|
//
|
||
|
// Returns: DWORD
|
||
|
//
|
||
|
// Purpose: Extracts the information transmitted in the section across
|
||
|
// sessions in the receiving process' context. Checks the
|
||
|
// signature written by Set.
|
||
|
//
|
||
|
// History: 2000-12-07 vtan created
|
||
|
// --------------------------------------------------------------------------
|
||
|
|
||
|
DWORD CInteractiveLogon::CRequestData::Get (WCHAR *pszUsername, WCHAR *pszDomain, WCHAR *pszPassword) const
|
||
|
|
||
|
{
|
||
|
DWORD dwErrorCode;
|
||
|
|
||
|
if (_ulMagicNumber == MAGIC_NUMBER)
|
||
|
{
|
||
|
UNICODE_STRING passwordString;
|
||
|
|
||
|
lstrcpy(pszUsername, _szUsername);
|
||
|
lstrcpy(pszDomain, _szDomain);
|
||
|
CopyMemory(pszPassword, _szPassword, (PWLEN + sizeof('\0')) * sizeof(WCHAR));
|
||
|
passwordString.Length = (PWLEN * sizeof(WCHAR));
|
||
|
passwordString.MaximumLength = (PWLEN + sizeof('\0')) * sizeof(WCHAR);
|
||
|
passwordString.Buffer = pszPassword;
|
||
|
RtlRunDecodeUnicodeString(_ucSeed, &passwordString);
|
||
|
pszPassword[_iPasswordLength] = L'\0';
|
||
|
dwErrorCode = ERROR_SUCCESS;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
dwErrorCode = ERROR_INVALID_PARAMETER;
|
||
|
}
|
||
|
return(dwErrorCode);
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------------------------------------
|
||
|
// CInteractiveLogon::CRequestData::SetErrorCode
|
||
|
//
|
||
|
// Arguments: dwErrorCode = Error code to set.
|
||
|
//
|
||
|
// Returns: DWORD
|
||
|
//
|
||
|
// Purpose: Sets the error code into the section.
|
||
|
//
|
||
|
// History: 2000-12-08 vtan created
|
||
|
// --------------------------------------------------------------------------
|
||
|
|
||
|
void CInteractiveLogon::CRequestData::SetErrorCode (DWORD dwErrorCode)
|
||
|
|
||
|
{
|
||
|
_dwErrorCode = dwErrorCode;
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------------------------------------
|
||
|
// CInteractiveLogon::CRequestData::GetErrorCode
|
||
|
//
|
||
|
// Arguments: <none>
|
||
|
//
|
||
|
// Returns: DWORD
|
||
|
//
|
||
|
// Purpose: Returns the error code from the section.
|
||
|
//
|
||
|
// History: 2000-12-08 vtan created
|
||
|
// --------------------------------------------------------------------------
|
||
|
|
||
|
DWORD CInteractiveLogon::CRequestData::GetErrorCode (void) const
|
||
|
|
||
|
{
|
||
|
return(_dwErrorCode);
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------------------------------------
|
||
|
// CInteractiveLogon::CRequestData::OpenEventReply
|
||
|
//
|
||
|
// Arguments: <none>
|
||
|
//
|
||
|
// Returns: HANDLE
|
||
|
//
|
||
|
// Purpose: Opens a handle to the reply event. The reply event is named
|
||
|
// in the section object.
|
||
|
//
|
||
|
// History: 2000-12-08 vtan created
|
||
|
// --------------------------------------------------------------------------
|
||
|
|
||
|
HANDLE CInteractiveLogon::CRequestData::OpenEventReply (void) const
|
||
|
|
||
|
{
|
||
|
return(OpenEvent(EVENT_MODIFY_STATE, FALSE, _szEventReplyName));
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------------------------------------
|
||
|
// CInteractiveLogon::CInteractiveLogon
|
||
|
//
|
||
|
// Arguments: <none>
|
||
|
//
|
||
|
// Returns: <none>
|
||
|
//
|
||
|
// Purpose: Constructor for CInteractiveLogon. Create a thread to wait
|
||
|
// on the auto-reset event signaled on an external request. This
|
||
|
// thread is cleaned up on object destruction and also on
|
||
|
// process termination.
|
||
|
//
|
||
|
// History: 2000-12-08 vtan created
|
||
|
// --------------------------------------------------------------------------
|
||
|
|
||
|
CInteractiveLogon::CInteractiveLogon (void) :
|
||
|
_hThread(NULL),
|
||
|
_fContinue(true),
|
||
|
_hwndHost(NULL)
|
||
|
|
||
|
{
|
||
|
Start();
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------------------------------------
|
||
|
// CInteractiveLogon::~CInteractiveLogon
|
||
|
//
|
||
|
// Arguments: <none>
|
||
|
//
|
||
|
// Returns: <none>
|
||
|
//
|
||
|
// Purpose: Terminate the wait thread. Queue an APC to set the member
|
||
|
// variable to end the termination. The wait is satisfied and
|
||
|
// returns (WAIT_IO_COMPLETION). The loop is exited and the
|
||
|
// thread is exited.
|
||
|
//
|
||
|
// History: 2000-12-08 vtan created
|
||
|
// --------------------------------------------------------------------------
|
||
|
|
||
|
CInteractiveLogon::~CInteractiveLogon (void)
|
||
|
|
||
|
{
|
||
|
Stop();
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------------------------------------
|
||
|
// CInteractiveLogon::Start
|
||
|
//
|
||
|
// Arguments: <none>
|
||
|
//
|
||
|
// Returns: <none>
|
||
|
//
|
||
|
// Purpose: Create the thread that listens on interactive logon requests.
|
||
|
//
|
||
|
// History: 2001-04-06 vtan created
|
||
|
// --------------------------------------------------------------------------
|
||
|
|
||
|
void CInteractiveLogon::Start (void)
|
||
|
|
||
|
{
|
||
|
if (_hThread == NULL)
|
||
|
{
|
||
|
DWORD dwThreadID;
|
||
|
|
||
|
_hThread = CreateThread(NULL,
|
||
|
0,
|
||
|
CB_ThreadProc,
|
||
|
this,
|
||
|
0,
|
||
|
&dwThreadID);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------------------------------------
|
||
|
// CInteractiveLogon::Stop
|
||
|
//
|
||
|
// Arguments: <none>
|
||
|
//
|
||
|
// Returns: <none>
|
||
|
//
|
||
|
// Purpose: Stop the thread that listens on interactive logon requests.
|
||
|
//
|
||
|
// History: 2001-04-06 vtan created
|
||
|
// --------------------------------------------------------------------------
|
||
|
|
||
|
void CInteractiveLogon::Stop (void)
|
||
|
|
||
|
{
|
||
|
HANDLE hThread;
|
||
|
|
||
|
hThread = InterlockedExchangePointer(&_hThread, NULL);
|
||
|
if (hThread != NULL)
|
||
|
{
|
||
|
if (QueueUserAPC(CB_APCProc, hThread, reinterpret_cast<ULONG_PTR>(this)) != FALSE)
|
||
|
{
|
||
|
(DWORD)WaitForSingleObject(hThread, INFINITE);
|
||
|
}
|
||
|
TBOOL(CloseHandle(hThread));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------------------------------------
|
||
|
// CInteractiveLogon::SetHostWindow
|
||
|
//
|
||
|
// Arguments: hwndHost = HWND of the actual UI host.
|
||
|
//
|
||
|
// Returns: <none>
|
||
|
//
|
||
|
// Purpose: Sets the HWND into the member variable so that the message
|
||
|
// can be sent directly to the UI host rather than the status
|
||
|
// host which is a go-between.
|
||
|
//
|
||
|
// History: 2000-12-08 vtan created
|
||
|
// --------------------------------------------------------------------------
|
||
|
|
||
|
void CInteractiveLogon::SetHostWindow (HWND hwndHost)
|
||
|
|
||
|
{
|
||
|
_hwndHost = hwndHost;
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------------------------------------
|
||
|
// CInteractiveLogon::Initiate
|
||
|
//
|
||
|
// Arguments: pszUsername = User name.
|
||
|
// pszDomain = Domain.
|
||
|
// pszPassword = Password.
|
||
|
// dwTimeout = Timeout value.
|
||
|
//
|
||
|
// Returns: DWORD
|
||
|
//
|
||
|
// Purpose: External entry point implementing interactive logon requests.
|
||
|
// This function checks for privileges and mutexes and events
|
||
|
// and does the right thing.
|
||
|
//
|
||
|
// History: 2001-04-06 vtan created
|
||
|
// --------------------------------------------------------------------------
|
||
|
|
||
|
DWORD CInteractiveLogon::Initiate (const WCHAR *pszUsername, const WCHAR *pszDomain, WCHAR *pszPassword, DWORD dwTimeout)
|
||
|
|
||
|
{
|
||
|
DWORD dwErrorCode;
|
||
|
|
||
|
dwErrorCode = CheckInteractiveLogonAllowed(dwTimeout);
|
||
|
if (ERROR_SUCCESS == dwErrorCode)
|
||
|
{
|
||
|
HANDLE hToken;
|
||
|
|
||
|
// First authenticate the user with the given credentials for an
|
||
|
// interactive logon. Go no further unless that's valid.
|
||
|
|
||
|
dwErrorCode = CTokenInformation::LogonUser(pszUsername,
|
||
|
pszDomain,
|
||
|
pszPassword,
|
||
|
&hToken);
|
||
|
if (ERROR_SUCCESS == dwErrorCode)
|
||
|
{
|
||
|
HANDLE hMutex;
|
||
|
|
||
|
hMutex = OpenMutex(SYNCHRONIZE | MUTEX_MODIFY_STATE, FALSE, SZ_INTERACTIVE_LOGON_REQUEST_MUTEX_NAME);
|
||
|
if (hMutex != NULL)
|
||
|
{
|
||
|
dwErrorCode = WaitForSingleObject(hMutex, dwTimeout);
|
||
|
if (WAIT_OBJECT_0 == dwErrorCode)
|
||
|
{
|
||
|
DWORD dwSessionID, dwUserSessionID;
|
||
|
HANDLE hEvent;
|
||
|
|
||
|
// User is authenticated correctly. There are several cases
|
||
|
// that need to be handled.
|
||
|
|
||
|
dwSessionID = USER_SHARED_DATA->ActiveConsoleId;
|
||
|
|
||
|
// Determine if the session has the welcome screen displayed
|
||
|
// by opening the named signal event for the session.
|
||
|
|
||
|
hEvent = OpenSessionNamedSignalEvent(dwSessionID);
|
||
|
if (hEvent != NULL)
|
||
|
{
|
||
|
TBOOL(CloseHandle(hEvent));
|
||
|
dwErrorCode = SendRequest(pszUsername, pszDomain, pszPassword);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
|
||
|
// Do whatever needs to be done to log the user on.
|
||
|
|
||
|
if (FoundUserSessionID(hToken, &dwUserSessionID))
|
||
|
{
|
||
|
if (dwUserSessionID == dwSessionID)
|
||
|
{
|
||
|
|
||
|
// User is the active console session. No further work needs
|
||
|
// to be done. Return success.
|
||
|
|
||
|
dwErrorCode = ERROR_SUCCESS;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
|
||
|
// User is disconnected. Reconnect back to the user session.
|
||
|
// If that fails then return the error code back.
|
||
|
|
||
|
if (WinStationConnect(SERVERNAME_CURRENT,
|
||
|
dwUserSessionID,
|
||
|
USER_SHARED_DATA->ActiveConsoleId,
|
||
|
L"",
|
||
|
TRUE) != FALSE)
|
||
|
{
|
||
|
dwErrorCode = ERROR_SUCCESS;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
dwErrorCode = GetLastError();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
HANDLE hEvent;
|
||
|
|
||
|
hEvent = CreateEvent(NULL, TRUE, FALSE, SZ_INTERACTIVE_LOGON_REPLY_EVENT_NAME);
|
||
|
if (hEvent != NULL)
|
||
|
{
|
||
|
|
||
|
// User has no session. If at the welcome screen then send the
|
||
|
// request to the welcome screen. Otherwise disconnect the
|
||
|
// current session and use a new session to log the user on.
|
||
|
|
||
|
dwErrorCode = ShellStartCredentialServer(pszUsername, pszDomain, pszPassword, dwTimeout);
|
||
|
if (ERROR_SUCCESS == dwErrorCode)
|
||
|
{
|
||
|
dwErrorCode = WaitForSingleObject(hEvent, dwTimeout);
|
||
|
}
|
||
|
TBOOL(CloseHandle(hEvent));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
dwErrorCode = GetLastError();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
TBOOL(ReleaseMutex(hMutex));
|
||
|
}
|
||
|
TBOOL(CloseHandle(hMutex));
|
||
|
}
|
||
|
TBOOL(CloseHandle(hToken));
|
||
|
}
|
||
|
}
|
||
|
return(dwErrorCode);
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------------------------------------
|
||
|
// CInteractiveLogon::CheckInteractiveLogonAllowed
|
||
|
//
|
||
|
// Arguments: dwTimeout = Timeout value.
|
||
|
//
|
||
|
// Returns: DWORD
|
||
|
//
|
||
|
// Purpose: Check whether the interactive logon request is allowed. To
|
||
|
// make this call:
|
||
|
//
|
||
|
// 1. You must have SE_TCB_PRIVILEGE.
|
||
|
// 2. There must be an active console session ID that's valid.
|
||
|
// 3. The machine must not be shutting down.
|
||
|
// 4. The logon mutex must be available.
|
||
|
//
|
||
|
// History: 2001-04-06 vtan created
|
||
|
// --------------------------------------------------------------------------
|
||
|
|
||
|
DWORD CInteractiveLogon::CheckInteractiveLogonAllowed (DWORD dwTimeout)
|
||
|
|
||
|
{
|
||
|
DWORD dwErrorCode;
|
||
|
|
||
|
// 1. Check for trusted call (SE_TCB_PRIVILEGE).
|
||
|
|
||
|
if (SHTestTokenPrivilege(NULL, SE_TCB_NAME) != FALSE)
|
||
|
{
|
||
|
|
||
|
// 2. Check for active console session.
|
||
|
|
||
|
if (USER_SHARED_DATA->ActiveConsoleId != static_cast<DWORD>(-1))
|
||
|
{
|
||
|
|
||
|
// 3. Check for machine shutdown.
|
||
|
|
||
|
dwErrorCode = CheckShutdown();
|
||
|
if (ERROR_SUCCESS == dwErrorCode)
|
||
|
{
|
||
|
|
||
|
// 4. Check for mutex availability.
|
||
|
|
||
|
dwErrorCode = CheckMutex(dwTimeout);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
dwErrorCode = ERROR_NOT_READY;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
dwErrorCode = ERROR_PRIVILEGE_NOT_HELD;
|
||
|
}
|
||
|
return(dwErrorCode);
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------------------------------------
|
||
|
// CInteractiveLogon::CheckShutdown
|
||
|
//
|
||
|
// Arguments: <none>
|
||
|
//
|
||
|
// Returns: DWORD
|
||
|
//
|
||
|
// Purpose: Returns an error code indicating if the machine is shutting
|
||
|
// down or not. If the event cannot be opened then the request
|
||
|
// is rejected.
|
||
|
//
|
||
|
// History: 2001-04-06 vtan created
|
||
|
// --------------------------------------------------------------------------
|
||
|
|
||
|
DWORD CInteractiveLogon::CheckShutdown (void)
|
||
|
|
||
|
{
|
||
|
DWORD dwErrorCode;
|
||
|
HANDLE hEvent;
|
||
|
|
||
|
hEvent = OpenEvent(SYNCHRONIZE, FALSE, SZ_SHUT_DOWN_EVENT_NAME);
|
||
|
if (hEvent != NULL)
|
||
|
{
|
||
|
if (WAIT_OBJECT_0 == WaitForSingleObject(hEvent, 0))
|
||
|
{
|
||
|
dwErrorCode = ERROR_SHUTDOWN_IN_PROGRESS;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
dwErrorCode = ERROR_SUCCESS;
|
||
|
}
|
||
|
TBOOL(CloseHandle(hEvent));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
dwErrorCode = GetLastError();
|
||
|
}
|
||
|
return(dwErrorCode);
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------------------------------------
|
||
|
// CInteractiveLogon::CheckMutex
|
||
|
//
|
||
|
// Arguments: dwTimeout = Timeout value.
|
||
|
//
|
||
|
// Returns: DWORD
|
||
|
//
|
||
|
// Purpose: Attempts to grab the logon mutex. This ensures that the state
|
||
|
// of winlogon is known and it's not busy processing a request.
|
||
|
//
|
||
|
// History: 2001-04-06 vtan created
|
||
|
// --------------------------------------------------------------------------
|
||
|
|
||
|
DWORD CInteractiveLogon::CheckMutex (DWORD dwTimeout)
|
||
|
|
||
|
{
|
||
|
DWORD dwErrorCode;
|
||
|
HANDLE hMutex;
|
||
|
|
||
|
hMutex = OpenMutex(SYNCHRONIZE, FALSE, SZ_INTERACTIVE_LOGON_MUTEX_NAME);
|
||
|
if (hMutex != NULL)
|
||
|
{
|
||
|
dwErrorCode = WaitForSingleObject(hMutex, dwTimeout);
|
||
|
if ((WAIT_OBJECT_0 == dwErrorCode) || (WAIT_ABANDONED == dwErrorCode))
|
||
|
{
|
||
|
TBOOL(ReleaseMutex(hMutex));
|
||
|
dwErrorCode = ERROR_SUCCESS;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
dwErrorCode = GetLastError();
|
||
|
}
|
||
|
return(dwErrorCode);
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------------------------------------
|
||
|
// CInteractiveLogon::FoundUserSessionID
|
||
|
//
|
||
|
// Arguments: hToken = Token of user session to find.
|
||
|
// pdwSessionID = Returned session ID.
|
||
|
//
|
||
|
// Returns: bool
|
||
|
//
|
||
|
// Purpose: Looks for a user session based on a given token. The match
|
||
|
// is made by user SID.
|
||
|
//
|
||
|
// History: 2001-04-06 vtan created
|
||
|
// --------------------------------------------------------------------------
|
||
|
|
||
|
bool CInteractiveLogon::FoundUserSessionID (HANDLE hToken, DWORD *pdwSessionID)
|
||
|
|
||
|
{
|
||
|
bool fResult;
|
||
|
PLOGONID pLogonIDs;
|
||
|
ULONG ulEntries;
|
||
|
|
||
|
fResult = false;
|
||
|
if (WinStationEnumerate(SERVERNAME_CURRENT, &pLogonIDs, &ulEntries) != FALSE)
|
||
|
{
|
||
|
ULONG ulIndex;
|
||
|
PLOGONID pLogonID;
|
||
|
|
||
|
for (ulIndex = 0, pLogonID = pLogonIDs; !fResult && (ulIndex < ulEntries); ++ulIndex, ++pLogonID)
|
||
|
{
|
||
|
if ((pLogonID->State == State_Active) || (pLogonID->State == State_Disconnected))
|
||
|
{
|
||
|
ULONG ulReturnLength;
|
||
|
WINSTATIONUSERTOKEN winStationUserToken;
|
||
|
|
||
|
winStationUserToken.ProcessId = ULongToHandle(GetCurrentProcessId());
|
||
|
winStationUserToken.ThreadId = ULongToHandle(GetCurrentThreadId());
|
||
|
winStationUserToken.UserToken = NULL;
|
||
|
if (WinStationQueryInformation(SERVERNAME_CURRENT,
|
||
|
pLogonID->SessionId,
|
||
|
WinStationUserToken,
|
||
|
&winStationUserToken,
|
||
|
sizeof(winStationUserToken),
|
||
|
&ulReturnLength) != FALSE)
|
||
|
{
|
||
|
fResult = CTokenInformation::IsSameUser(hToken, winStationUserToken.UserToken);
|
||
|
if (fResult)
|
||
|
{
|
||
|
*pdwSessionID = pLogonID->SessionId;
|
||
|
}
|
||
|
TBOOL(CloseHandle(winStationUserToken.UserToken));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Free any resources used.
|
||
|
|
||
|
(BOOLEAN)WinStationFreeMemory(pLogonIDs);
|
||
|
}
|
||
|
return(fResult);
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------------------------------------
|
||
|
// CInteractiveLogon::SendRequest
|
||
|
//
|
||
|
// Arguments: pszUsername = Username.
|
||
|
// pszDomain = Domain.
|
||
|
// pszPassword = Password. This string must be writable.
|
||
|
//
|
||
|
// Returns: DWORD
|
||
|
//
|
||
|
// Purpose: This function knows how to transmit the interactive logon
|
||
|
// request from (presumably) session 0 to whatever session is
|
||
|
// the active console session ID.
|
||
|
//
|
||
|
// pszUsername must be UNLEN + sizeof('\0') characters.
|
||
|
// pszDomain must be DNLEN + sizeof('\0') characters.
|
||
|
// pszPassword must be PWLEN + sizeof('\0') characters.
|
||
|
//
|
||
|
// pszPassword must be writable. The password is copied and
|
||
|
// encoded and erased from the source buffer.
|
||
|
//
|
||
|
// History: 2000-12-07 vtan created
|
||
|
// --------------------------------------------------------------------------
|
||
|
|
||
|
DWORD CInteractiveLogon::SendRequest (const WCHAR *pszUsername, const WCHAR *pszDomain, WCHAR *pszPassword)
|
||
|
|
||
|
{
|
||
|
DWORD dwErrorCode, dwActiveConsoleID;
|
||
|
HANDLE hEventReply;
|
||
|
|
||
|
dwErrorCode = ERROR_ACCESS_DENIED;
|
||
|
|
||
|
// First get the active console session ID.
|
||
|
|
||
|
dwActiveConsoleID = USER_SHARED_DATA->ActiveConsoleId;
|
||
|
|
||
|
// Create a named event in that session named object space.
|
||
|
|
||
|
hEventReply = CreateSessionNamedReplyEvent(dwActiveConsoleID);
|
||
|
if (hEventReply != NULL)
|
||
|
{
|
||
|
HANDLE hEventSignal;
|
||
|
|
||
|
hEventSignal = OpenSessionNamedSignalEvent(dwActiveConsoleID);
|
||
|
if (hEventSignal != NULL)
|
||
|
{
|
||
|
HANDLE hSection;
|
||
|
|
||
|
// Create a named section that the UI host will open. This code
|
||
|
// is executed in the service context so it's always on session 0.
|
||
|
|
||
|
hSection = CreateSessionNamedSection(dwActiveConsoleID);
|
||
|
if (hSection != NULL)
|
||
|
{
|
||
|
void *pV;
|
||
|
|
||
|
// Map the section into this process address space so we can put
|
||
|
// stuff it in.
|
||
|
|
||
|
pV = MapViewOfFile(hSection,
|
||
|
FILE_MAP_WRITE,
|
||
|
0,
|
||
|
0,
|
||
|
0);
|
||
|
if (pV != NULL)
|
||
|
{
|
||
|
__try
|
||
|
{
|
||
|
DWORD dwWaitResult;
|
||
|
CRequestData *pRequestData;
|
||
|
|
||
|
// Fill the section data with the information given.
|
||
|
|
||
|
pRequestData = static_cast<CRequestData*>(pV);
|
||
|
pRequestData->Set(pszUsername, pszDomain, pszPassword);
|
||
|
|
||
|
// Wake up the waiting thread in the UI host.
|
||
|
|
||
|
TBOOL(SetEvent(hEventSignal));
|
||
|
|
||
|
// Wait 15 seconds for a reply the UI host.
|
||
|
|
||
|
dwWaitResult = WaitForSingleObject(hEventReply, 15000);
|
||
|
|
||
|
// Return an error code accordingly.
|
||
|
|
||
|
if (WAIT_OBJECT_0 == dwWaitResult)
|
||
|
{
|
||
|
dwErrorCode = pRequestData->GetErrorCode();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
dwErrorCode = dwWaitResult;
|
||
|
}
|
||
|
}
|
||
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
||
|
{
|
||
|
dwErrorCode = ERROR_OUTOFMEMORY;
|
||
|
}
|
||
|
TBOOL(UnmapViewOfFile(pV));
|
||
|
}
|
||
|
TBOOL(CloseHandle(hSection));
|
||
|
}
|
||
|
TBOOL(CloseHandle(hEventSignal));
|
||
|
}
|
||
|
TBOOL(CloseHandle(hEventReply));
|
||
|
}
|
||
|
return(dwErrorCode);
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------------------------------------
|
||
|
// CInteractiveLogon::FormulateObjectBasePath
|
||
|
//
|
||
|
// Arguments: dwSessionID = Session ID of the named object space.
|
||
|
// pszObjectPath = Buffer to receive path.
|
||
|
//
|
||
|
// Returns: <none>
|
||
|
//
|
||
|
// Purpose: Creates the correct path to the named object space for the
|
||
|
// given session ID.
|
||
|
//
|
||
|
// History: 2000-12-08 vtan created
|
||
|
// --------------------------------------------------------------------------
|
||
|
|
||
|
void CInteractiveLogon::FormulateObjectBasePath (DWORD dwSessionID, WCHAR *pszObjectPath)
|
||
|
|
||
|
{
|
||
|
if (dwSessionID == 0)
|
||
|
{
|
||
|
(WCHAR*)lstrcpyW(pszObjectPath, L"\\BaseNamedObjects\\");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
wsprintfW(pszObjectPath, L"\\Sessions\\%d\\BaseNamedObjects\\", dwSessionID);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------------------------------------
|
||
|
// CInteractiveLogon::CreateSessionNamedReplyEvent
|
||
|
//
|
||
|
// Arguments: dwSessionID = Session ID.
|
||
|
//
|
||
|
// Returns: HANDLE
|
||
|
//
|
||
|
// Purpose: Creates the named reply event in the target session ID.
|
||
|
//
|
||
|
// History: 2000-12-08 vtan created
|
||
|
// --------------------------------------------------------------------------
|
||
|
|
||
|
HANDLE CInteractiveLogon::CreateSessionNamedReplyEvent (DWORD dwSessionID)
|
||
|
|
||
|
{
|
||
|
NTSTATUS status;
|
||
|
HANDLE hEvent;
|
||
|
OBJECT_ATTRIBUTES objectAttributes;
|
||
|
UNICODE_STRING eventName;
|
||
|
WCHAR szEventName[128];
|
||
|
|
||
|
FormulateObjectBasePath(dwSessionID, szEventName);
|
||
|
(WCHAR*)lstrcatW(szEventName, s_szEventReplyName);
|
||
|
RtlInitUnicodeString(&eventName, szEventName);
|
||
|
InitializeObjectAttributes(&objectAttributes,
|
||
|
&eventName,
|
||
|
0,
|
||
|
NULL,
|
||
|
NULL);
|
||
|
status = NtCreateEvent(&hEvent,
|
||
|
EVENT_ALL_ACCESS,
|
||
|
&objectAttributes,
|
||
|
SynchronizationEvent,
|
||
|
FALSE);
|
||
|
if (!NT_SUCCESS(status))
|
||
|
{
|
||
|
hEvent = NULL;
|
||
|
}
|
||
|
return(hEvent);
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------------------------------------
|
||
|
// CInteractiveLogon::OpenSessionNamedSignalEvent
|
||
|
//
|
||
|
// Arguments: dwSessionID = Session ID.
|
||
|
//
|
||
|
// Returns: HANDLE
|
||
|
//
|
||
|
// Purpose: Opens the named signal event in the target session ID.
|
||
|
//
|
||
|
// History: 2000-12-08 vtan created
|
||
|
// --------------------------------------------------------------------------
|
||
|
|
||
|
HANDLE CInteractiveLogon::OpenSessionNamedSignalEvent (DWORD dwSessionID)
|
||
|
|
||
|
{
|
||
|
NTSTATUS status;
|
||
|
HANDLE hEvent;
|
||
|
OBJECT_ATTRIBUTES objectAttributes;
|
||
|
UNICODE_STRING eventName;
|
||
|
WCHAR szEventName[128];
|
||
|
|
||
|
FormulateObjectBasePath(dwSessionID, szEventName);
|
||
|
(WCHAR*)lstrcatW(szEventName, s_szEventSignalName);
|
||
|
RtlInitUnicodeString(&eventName, szEventName);
|
||
|
InitializeObjectAttributes(&objectAttributes,
|
||
|
&eventName,
|
||
|
0,
|
||
|
NULL,
|
||
|
NULL);
|
||
|
status = NtOpenEvent(&hEvent,
|
||
|
EVENT_MODIFY_STATE,
|
||
|
&objectAttributes);
|
||
|
if (!NT_SUCCESS(status))
|
||
|
{
|
||
|
hEvent = NULL;
|
||
|
}
|
||
|
return(hEvent);
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------------------------------------
|
||
|
// CInteractiveLogon::CreateSessionNamedSection
|
||
|
//
|
||
|
// Arguments: dwSessionID = Session ID.
|
||
|
//
|
||
|
// Returns: HANDLE
|
||
|
//
|
||
|
// Purpose: Creates a named section object in the target session ID.
|
||
|
//
|
||
|
// History: 2000-12-08 vtan created
|
||
|
// --------------------------------------------------------------------------
|
||
|
|
||
|
HANDLE CInteractiveLogon::CreateSessionNamedSection (DWORD dwSessionID)
|
||
|
|
||
|
{
|
||
|
NTSTATUS status;
|
||
|
HANDLE hSection;
|
||
|
OBJECT_ATTRIBUTES objectAttributes;
|
||
|
UNICODE_STRING sectionName;
|
||
|
LARGE_INTEGER sectionSize;
|
||
|
WCHAR szSectionName[128];
|
||
|
|
||
|
FormulateObjectBasePath(dwSessionID, szSectionName);
|
||
|
(WCHAR*)lstrcatW(szSectionName, s_szSectionName);
|
||
|
RtlInitUnicodeString(§ionName, szSectionName);
|
||
|
InitializeObjectAttributes(&objectAttributes,
|
||
|
§ionName,
|
||
|
0,
|
||
|
NULL,
|
||
|
NULL);
|
||
|
sectionSize.LowPart = sizeof(CRequestData);
|
||
|
sectionSize.HighPart = 0;
|
||
|
status = NtCreateSection(&hSection,
|
||
|
STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_WRITE | SECTION_MAP_READ,
|
||
|
&objectAttributes,
|
||
|
§ionSize,
|
||
|
PAGE_READWRITE,
|
||
|
SEC_COMMIT,
|
||
|
NULL);
|
||
|
if (!NT_SUCCESS(status))
|
||
|
{
|
||
|
hSection = NULL;
|
||
|
}
|
||
|
return(hSection);
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------------------------------------
|
||
|
// CInteractiveLogon::WaitForInteractiveLogonRequest
|
||
|
//
|
||
|
// Arguments: <none>
|
||
|
//
|
||
|
// Returns: <none>
|
||
|
//
|
||
|
// Purpose: Thread that executes in the UI host context of the receiving
|
||
|
// session. This thread waits in an alertable state for the
|
||
|
// signal event. If the event is signaled it does work to log the
|
||
|
// specified user on.
|
||
|
//
|
||
|
// History: 2000-12-08 vtan created
|
||
|
// --------------------------------------------------------------------------
|
||
|
|
||
|
void CInteractiveLogon::WaitForInteractiveLogonRequest (void)
|
||
|
|
||
|
{
|
||
|
HANDLE hEvent;
|
||
|
|
||
|
hEvent = CreateEvent(NULL,
|
||
|
FALSE,
|
||
|
FALSE,
|
||
|
s_szEventSignalName);
|
||
|
if (hEvent != NULL)
|
||
|
{
|
||
|
DWORD dwWaitResult;
|
||
|
|
||
|
while (_fContinue)
|
||
|
{
|
||
|
dwWaitResult = WaitForSingleObjectEx(hEvent, INFINITE, TRUE);
|
||
|
if (WAIT_OBJECT_0 == dwWaitResult)
|
||
|
{
|
||
|
HANDLE hSection;
|
||
|
|
||
|
hSection = OpenFileMapping(FILE_MAP_WRITE,
|
||
|
FALSE,
|
||
|
s_szSectionName);
|
||
|
if (hSection != NULL)
|
||
|
{
|
||
|
void *pV;
|
||
|
|
||
|
pV = MapViewOfFile(hSection,
|
||
|
FILE_MAP_WRITE,
|
||
|
0,
|
||
|
0,
|
||
|
0);
|
||
|
if (pV != NULL)
|
||
|
{
|
||
|
__try
|
||
|
{
|
||
|
DWORD dwErrorCode;
|
||
|
HANDLE hEventReply;
|
||
|
CRequestData *pRequestData;
|
||
|
INTERACTIVE_LOGON_REQUEST interactiveLogonRequest;
|
||
|
|
||
|
pRequestData = static_cast<CRequestData*>(pV);
|
||
|
hEventReply = pRequestData->OpenEventReply();
|
||
|
if (hEventReply != NULL)
|
||
|
{
|
||
|
dwErrorCode = pRequestData->Get(interactiveLogonRequest.szUsername,
|
||
|
interactiveLogonRequest.szDomain,
|
||
|
interactiveLogonRequest.szPassword);
|
||
|
if (ERROR_SUCCESS == dwErrorCode)
|
||
|
{
|
||
|
dwErrorCode = static_cast<DWORD>(SendMessage(_hwndHost, WM_UIHOSTMESSAGE, HM_INTERACTIVE_LOGON_REQUEST, reinterpret_cast<LPARAM>(&interactiveLogonRequest)));
|
||
|
}
|
||
|
pRequestData->SetErrorCode(dwErrorCode);
|
||
|
TBOOL(SetEvent(hEventReply));
|
||
|
TBOOL(CloseHandle(hEventReply));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
dwErrorCode = GetLastError();
|
||
|
pRequestData->SetErrorCode(dwErrorCode);
|
||
|
}
|
||
|
}
|
||
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
||
|
{
|
||
|
}
|
||
|
TBOOL(UnmapViewOfFile(pV));
|
||
|
}
|
||
|
TBOOL(CloseHandle(hSection));
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ASSERTMSG((WAIT_FAILED == dwWaitResult) || (WAIT_IO_COMPLETION == dwWaitResult), "Unexpected result from kernel32!WaitForSingleObjectEx in CInteractiveLogon::WaitForInteractiveLogonRequest");
|
||
|
_fContinue = false;
|
||
|
}
|
||
|
}
|
||
|
TBOOL(CloseHandle(hEvent));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------------------------------------
|
||
|
// CInteractiveLogon::CB_ThreadProc
|
||
|
//
|
||
|
// Arguments: pParameter = this object.
|
||
|
//
|
||
|
// Returns: DWORD
|
||
|
//
|
||
|
// Purpose: Callback function stub to member function.
|
||
|
//
|
||
|
// History: 2000-12-08 vtan created
|
||
|
// --------------------------------------------------------------------------
|
||
|
|
||
|
DWORD WINAPI CInteractiveLogon::CB_ThreadProc (void *pParameter)
|
||
|
|
||
|
{
|
||
|
static_cast<CInteractiveLogon*>(pParameter)->WaitForInteractiveLogonRequest();
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------------------------------------
|
||
|
// CInteractiveLogon::CB_APCProc
|
||
|
//
|
||
|
// Arguments: dwParam = this object.
|
||
|
//
|
||
|
// Returns: <none>
|
||
|
//
|
||
|
// Purpose: Set object member variable to exit thread loop.
|
||
|
//
|
||
|
// History: 2000-12-08 vtan created
|
||
|
// --------------------------------------------------------------------------
|
||
|
|
||
|
void CALLBACK CInteractiveLogon::CB_APCProc (ULONG_PTR dwParam)
|
||
|
|
||
|
{
|
||
|
reinterpret_cast<CInteractiveLogon*>(dwParam)->_fContinue = false;
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------------------------------------
|
||
|
// ::InitiateInteractiveLogon
|
||
|
//
|
||
|
// Arguments: pszUsername = User name.
|
||
|
// pszPassword = Password.
|
||
|
// dwTimeout = Time out in milliseconds.
|
||
|
//
|
||
|
// Returns: BOOL
|
||
|
//
|
||
|
// Purpose: External entry point function exported by name to initiate
|
||
|
// an interactive logon with specified timeout.
|
||
|
//
|
||
|
// History: 2001-04-10 vtan created
|
||
|
// 2001-06-04 vtan added timeout
|
||
|
// --------------------------------------------------------------------------
|
||
|
|
||
|
EXTERN_C BOOL WINAPI InitiateInteractiveLogon (const WCHAR *pszUsername, WCHAR *pszPassword, DWORD dwTimeout)
|
||
|
|
||
|
{
|
||
|
DWORD dwErrorCode;
|
||
|
|
||
|
dwErrorCode = CInteractiveLogon::Initiate(pszUsername, L"", pszPassword, dwTimeout);
|
||
|
if (ERROR_SUCCESS != dwErrorCode)
|
||
|
{
|
||
|
SetLastError(dwErrorCode);
|
||
|
}
|
||
|
return(ERROR_SUCCESS == dwErrorCode);
|
||
|
}
|
||
|
|