516 lines
18 KiB
C++
516 lines
18 KiB
C++
|
// --------------------------------------------------------------------------
|
||
|
// Module Name: LogonIPC.cpp
|
||
|
//
|
||
|
// Copyright (c) 1999, Microsoft Corporation
|
||
|
//
|
||
|
// Class that implements communication between an external process and the
|
||
|
// GINA logon dialog.
|
||
|
//
|
||
|
// History: 1999-08-20 vtan created
|
||
|
// 2000-01-31 vtan moved from Neptune to Whistler
|
||
|
// --------------------------------------------------------------------------
|
||
|
|
||
|
#include "priv.h"
|
||
|
#include "limits.h"
|
||
|
#include "LogonIPC.h"
|
||
|
|
||
|
#include "GinaIPC.h"
|
||
|
|
||
|
// --------------------------------------------------------------------------
|
||
|
// CLogonIPC::CLogonIPC
|
||
|
//
|
||
|
// Arguments: <none>
|
||
|
//
|
||
|
// Returns: <none>
|
||
|
//
|
||
|
// Purpose: Initializes the CLogonIPC class.
|
||
|
//
|
||
|
// History: 1999-08-20 vtan created
|
||
|
// --------------------------------------------------------------------------
|
||
|
|
||
|
CLogonIPC::CLogonIPC (void) :
|
||
|
_iLogonAttemptCount(0),
|
||
|
_hwndLogonService(NULL)
|
||
|
|
||
|
{
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------------------------------------
|
||
|
// CLogonIPC::~CLogonIPC
|
||
|
//
|
||
|
// Arguments: <none>
|
||
|
//
|
||
|
// Returns: <none>
|
||
|
//
|
||
|
// Purpose: Releases any resources used by the CLogonIPC class.
|
||
|
//
|
||
|
// History: 1999-08-20 vtan created
|
||
|
// --------------------------------------------------------------------------
|
||
|
|
||
|
CLogonIPC::~CLogonIPC (void)
|
||
|
|
||
|
{
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------------------------------------
|
||
|
// CLogonIPC::IsLogonServiceAvailable
|
||
|
//
|
||
|
// Arguments: <none>
|
||
|
//
|
||
|
// Returns: bool = Presence or abscence.
|
||
|
//
|
||
|
// Purpose: Finds out if the window providing logon service in GINA is
|
||
|
// available. The determination is not performed statically but
|
||
|
// rather dynamically which allows this class to be hosted by
|
||
|
// the actual window providing the service as well.
|
||
|
//
|
||
|
// History: 1999-08-20 vtan created
|
||
|
// --------------------------------------------------------------------------
|
||
|
|
||
|
bool CLogonIPC::IsLogonServiceAvailable (void)
|
||
|
|
||
|
{
|
||
|
_hwndLogonService = FindWindow(NULL, TEXT("GINA Logon"));
|
||
|
return(_hwndLogonService != NULL);
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------------------------------------
|
||
|
// CLogonIPC::IsUserLoggedOn
|
||
|
//
|
||
|
// Arguments: pwszUsername = User name.
|
||
|
// pwszDomain = User domain.
|
||
|
//
|
||
|
// Returns: bool = Presence or abscence.
|
||
|
//
|
||
|
// Purpose: Finds out if the given user is logged onto the system. You
|
||
|
// may pass a NULL pwszDomain for the local machine.
|
||
|
//
|
||
|
// History: 1999-08-20 vtan created
|
||
|
// --------------------------------------------------------------------------
|
||
|
|
||
|
bool CLogonIPC::IsUserLoggedOn (const WCHAR *pwszUsername, const WCHAR *pwszDomain)
|
||
|
|
||
|
{
|
||
|
LOGONIPC_USERID logonIPCUserID;
|
||
|
|
||
|
PackageIdentification(pwszUsername, pwszDomain, &logonIPCUserID);
|
||
|
return(SendToLogonService(LOGON_QUERY_LOGGED_ON, &logonIPCUserID, sizeof(logonIPCUserID), true));
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------------------------------------
|
||
|
// CLogonIPC::LogUserOn
|
||
|
//
|
||
|
// Arguments: pwszUsername = User name.
|
||
|
// pwszDomain = User domain.
|
||
|
// pwszPassword = User password. This is passed clear text.
|
||
|
// Once encoded the password buffer is
|
||
|
// zeroed. This function owns the memory that
|
||
|
// you pass in.
|
||
|
//
|
||
|
// Returns: bool = Success or failure.
|
||
|
//
|
||
|
// Purpose: Attempts to log the user with the given credentials onto the
|
||
|
// system. The password buffer is owned by this function for the
|
||
|
// purpose of clearing it once encoded. Failed logon attempts
|
||
|
// cause a counter to be incremented and a subsequent delay using
|
||
|
// that counter is done to slow dictionary attacks.
|
||
|
//
|
||
|
// History: 1999-08-20 vtan created
|
||
|
// --------------------------------------------------------------------------
|
||
|
|
||
|
bool CLogonIPC::LogUserOn (const WCHAR *pwszUsername, const WCHAR *pwszDomain, WCHAR *pwszPassword)
|
||
|
|
||
|
{
|
||
|
bool fResult;
|
||
|
int iPasswordLength, iTruePasswordLength;
|
||
|
UNICODE_STRING passwordString;
|
||
|
LOGONIPC_CREDENTIALS logonIPCCredentials;
|
||
|
|
||
|
PackageIdentification(pwszUsername, pwszDomain, &logonIPCCredentials.userID);
|
||
|
|
||
|
// Limit the password to 127 characters. RtlRunEncodeUnicodeString
|
||
|
// does not support strings greater than 127 characters.
|
||
|
|
||
|
iTruePasswordLength = iPasswordLength = lstrlenW(pwszPassword);
|
||
|
if (iPasswordLength > 127)
|
||
|
{
|
||
|
iPasswordLength = 127;
|
||
|
}
|
||
|
pwszPassword[iPasswordLength] = L'\0';
|
||
|
lstrcpyW(logonIPCCredentials.wszPassword, pwszPassword);
|
||
|
logonIPCCredentials.iPasswordLength = iPasswordLength;
|
||
|
ZeroMemory(pwszPassword, (iTruePasswordLength + sizeof('\0')) * sizeof(WCHAR));
|
||
|
logonIPCCredentials.ucPasswordSeed = static_cast<unsigned char>(GetTickCount());
|
||
|
RtlInitUnicodeString(&passwordString, logonIPCCredentials.wszPassword);
|
||
|
RtlRunEncodeUnicodeString(&logonIPCCredentials.ucPasswordSeed, &passwordString);
|
||
|
fResult = SendToLogonService(LOGON_LOGON_USER, &logonIPCCredentials, sizeof(logonIPCCredentials), false);
|
||
|
if (!fResult)
|
||
|
{
|
||
|
Sleep(_iLogonAttemptCount * 1000);
|
||
|
if (_iLogonAttemptCount < 5)
|
||
|
{
|
||
|
++_iLogonAttemptCount;
|
||
|
}
|
||
|
}
|
||
|
return(fResult);
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------------------------------------
|
||
|
// CLogonIPC::LogUserOff
|
||
|
//
|
||
|
// Arguments: pwszUsername = User name.
|
||
|
// pwszDomain = User domain.
|
||
|
//
|
||
|
// Returns: bool = Success or failure.
|
||
|
//
|
||
|
// Purpose: Attempts to log the given user off the system. This will fail
|
||
|
// if they aren't logged on.
|
||
|
//
|
||
|
// History: 1999-08-20 vtan created
|
||
|
// --------------------------------------------------------------------------
|
||
|
|
||
|
bool CLogonIPC::LogUserOff (const WCHAR *pwszUsername, const WCHAR *pwszDomain)
|
||
|
|
||
|
{
|
||
|
LOGONIPC_USERID logonIPCUserID;
|
||
|
|
||
|
PackageIdentification(pwszUsername, pwszDomain, &logonIPCUserID);
|
||
|
return(SendToLogonService(LOGON_LOGOFF_USER, &logonIPCUserID, sizeof(logonIPCUserID), true));
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------------------------------------
|
||
|
// CLogonIPC::TestBlankPassword
|
||
|
//
|
||
|
// Arguments: pwszUsername = User name.
|
||
|
// pwszDomain = User domain.
|
||
|
//
|
||
|
// Returns: bool = Success or failure.
|
||
|
//
|
||
|
// Purpose: Attempts to log the given user on the system with a blank
|
||
|
// password. The token is then dump and failure/success returned.
|
||
|
//
|
||
|
// History: 2000-03-09 vtan created
|
||
|
// --------------------------------------------------------------------------
|
||
|
|
||
|
bool CLogonIPC::TestBlankPassword (const WCHAR *pwszUsername, const WCHAR *pwszDomain)
|
||
|
|
||
|
{
|
||
|
LOGONIPC_USERID logonIPCUserID;
|
||
|
|
||
|
PackageIdentification(pwszUsername, pwszDomain, &logonIPCUserID);
|
||
|
return(SendToLogonService(LOGON_TEST_BLANK_PASSWORD, &logonIPCUserID, sizeof(logonIPCUserID), true));
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------------------------------------
|
||
|
// CLogonIPC::TestInteractiveLogonAllowed
|
||
|
//
|
||
|
// Arguments: pwszUsername = User name.
|
||
|
// pwszDomain = User domain.
|
||
|
//
|
||
|
// Returns: bool
|
||
|
//
|
||
|
// Purpose: Test whether the user has interactive logon rights to this
|
||
|
// machine. The presence of SeDenyInteractiveLogonRight
|
||
|
// determines this - NOT the presence of SeInteractiveLogonRight.
|
||
|
//
|
||
|
// History: 2000-08-15 vtan created
|
||
|
// --------------------------------------------------------------------------
|
||
|
|
||
|
bool CLogonIPC::TestInteractiveLogonAllowed (const WCHAR *pwszUsername, const WCHAR *pwszDomain)
|
||
|
|
||
|
{
|
||
|
LOGONIPC_USERID logonIPCUserID;
|
||
|
|
||
|
PackageIdentification(pwszUsername, pwszDomain, &logonIPCUserID);
|
||
|
return(SendToLogonService(LOGON_TEST_INTERACTIVE_LOGON_ALLOWED, &logonIPCUserID, sizeof(logonIPCUserID), true));
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------------------------------------
|
||
|
// CLogonIPC::TestEjectAllowed
|
||
|
//
|
||
|
// Arguments: <none>
|
||
|
//
|
||
|
// Returns: bool = Success or failure.
|
||
|
//
|
||
|
// Purpose: Tests whether the computer is ejectable (docked laptop).
|
||
|
//
|
||
|
// History: 2001-01-10 vtan created
|
||
|
// --------------------------------------------------------------------------
|
||
|
|
||
|
bool CLogonIPC::TestEjectAllowed (void)
|
||
|
|
||
|
{
|
||
|
LOGONIPC logonIPC;
|
||
|
|
||
|
return(SendToLogonService(LOGON_TEST_EJECT_ALLOWED, &logonIPC, sizeof(logonIPC), true));
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------------------------------------
|
||
|
// CLogonIPC::TestShutdownAllowed
|
||
|
//
|
||
|
// Arguments: <none>
|
||
|
//
|
||
|
// Returns: bool = Success or failure.
|
||
|
//
|
||
|
// Purpose: Tests whether the computer can be shut down.
|
||
|
//
|
||
|
// History: 2001-02-22 vtan created
|
||
|
// --------------------------------------------------------------------------
|
||
|
|
||
|
bool CLogonIPC::TestShutdownAllowed (void)
|
||
|
|
||
|
{
|
||
|
LOGONIPC logonIPC;
|
||
|
|
||
|
return(SendToLogonService(LOGON_TEST_SHUTDOWN_ALLOWED, &logonIPC, sizeof(logonIPC), true));
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------------------------------------
|
||
|
// CLogonIPC::TurnOffComputer
|
||
|
//
|
||
|
// Arguments: <none>
|
||
|
//
|
||
|
// Returns: bool = Success or failure.
|
||
|
//
|
||
|
// Purpose: Brings up the "Turn Off Computer" dialog and allows the user
|
||
|
// to choose what to do.
|
||
|
//
|
||
|
// History: 2000-04-20 vtan created
|
||
|
// --------------------------------------------------------------------------
|
||
|
|
||
|
bool CLogonIPC::TurnOffComputer (void)
|
||
|
|
||
|
{
|
||
|
LOGONIPC logonIPC;
|
||
|
|
||
|
return(SendToLogonService(LOGON_TURN_OFF_COMPUTER, &logonIPC, sizeof(logonIPC), false));
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------------------------------------
|
||
|
// CLogonIPC::EjectComputer
|
||
|
//
|
||
|
// Arguments: <none>
|
||
|
//
|
||
|
// Returns: bool = Success or failure.
|
||
|
//
|
||
|
// Purpose: Ejects the computer (docked laptop).
|
||
|
//
|
||
|
// History: 2001-01-10 vtan created
|
||
|
// --------------------------------------------------------------------------
|
||
|
|
||
|
bool CLogonIPC::EjectComputer (void)
|
||
|
|
||
|
{
|
||
|
LOGONIPC logonIPC;
|
||
|
|
||
|
return(SendToLogonService(LOGON_EJECT_COMPUTER, &logonIPC, sizeof(logonIPC), true));
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------------------------------------
|
||
|
// CLogonIPC::SignalUIHostFailure
|
||
|
//
|
||
|
// Arguments: <none>
|
||
|
//
|
||
|
// Returns: bool
|
||
|
//
|
||
|
// Purpose: Called when the UI host has an error that it cannot recover
|
||
|
// from. This signals msgina to fall back to classic mode.
|
||
|
//
|
||
|
// History: 2000-03-09 vtan created
|
||
|
// --------------------------------------------------------------------------
|
||
|
|
||
|
bool CLogonIPC::SignalUIHostFailure (void)
|
||
|
|
||
|
{
|
||
|
LOGONIPC logonIPC;
|
||
|
|
||
|
return(SendToLogonService(LOGON_SIGNAL_UIHOST_FAILURE, &logonIPC, sizeof(logonIPC), true));
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------------------------------------
|
||
|
// CLogonIPC::AllowExternalCredentials
|
||
|
//
|
||
|
// Arguments: <none>
|
||
|
//
|
||
|
// Returns: bool = Success or failure.
|
||
|
//
|
||
|
// Purpose:
|
||
|
//
|
||
|
// History: 2000-06-26 vtan created
|
||
|
// --------------------------------------------------------------------------
|
||
|
|
||
|
bool CLogonIPC::AllowExternalCredentials (void)
|
||
|
|
||
|
{
|
||
|
LOGONIPC logonIPC;
|
||
|
|
||
|
return(SendToLogonService(LOGON_ALLOW_EXTERNAL_CREDENTIALS, &logonIPC, sizeof(logonIPC), true));
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------------------------------------
|
||
|
// CLogonIPC::RequestExternalCredentials
|
||
|
//
|
||
|
// Arguments: <none>
|
||
|
//
|
||
|
// Returns: bool
|
||
|
//
|
||
|
// Purpose:
|
||
|
//
|
||
|
// History: 2000-06-26 vtan created
|
||
|
// --------------------------------------------------------------------------
|
||
|
|
||
|
bool CLogonIPC::RequestExternalCredentials (void)
|
||
|
|
||
|
{
|
||
|
LOGONIPC logonIPC;
|
||
|
|
||
|
return(SendToLogonService(LOGON_REQUEST_EXTERNAL_CREDENTIALS, &logonIPC, sizeof(logonIPC), true));
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------------------------------------
|
||
|
// CLogonIPC::PackageIdentification
|
||
|
//
|
||
|
// Arguments: pwszUsername = User name.
|
||
|
// pwszDomain = User domain.
|
||
|
// pIdentification = Pointer to a LOGONIPC_USERID struct
|
||
|
// which is masked as void* to allow
|
||
|
// LogonIPC.h to not expose this detail.
|
||
|
//
|
||
|
// Returns: <none>
|
||
|
//
|
||
|
// Purpose: Takes the user name and domain and packages them into the
|
||
|
// given struct. If no domain is given the a zero length string
|
||
|
// is used which indicates to the logon service provider that
|
||
|
// the local machine is desired.
|
||
|
//
|
||
|
// Now parses the user name given. If the user has "\" then it
|
||
|
// is assumed to be of the form "DOMAIN\USER". If the user has
|
||
|
// "@" then it is assumed to be a UPN name.
|
||
|
//
|
||
|
// History: 1999-08-20 vtan created
|
||
|
// 2000-06-27 vtan added UPN and DOMAIN parsing support
|
||
|
// --------------------------------------------------------------------------
|
||
|
|
||
|
void CLogonIPC::PackageIdentification (const WCHAR *pwszUsername, const WCHAR *pwszDomain, void *pIdentification)
|
||
|
|
||
|
{
|
||
|
bool fDone;
|
||
|
int i, iStringLength;
|
||
|
LOGONIPC_USERID *pLogonIPCUserID;
|
||
|
|
||
|
pLogonIPCUserID = reinterpret_cast<LOGONIPC_USERID*>(pIdentification);
|
||
|
iStringLength = lstrlen(pwszUsername);
|
||
|
for (fDone = false, i = 0; !fDone && (i < iStringLength); ++i)
|
||
|
{
|
||
|
if (pwszUsername[i] == L'\\')
|
||
|
{
|
||
|
lstrcpynW(pLogonIPCUserID->wszDomain, pwszUsername, ARRAYSIZE(pLogonIPCUserID->wszDomain));
|
||
|
pLogonIPCUserID->wszDomain[i] = L'\0';
|
||
|
++i;
|
||
|
lstrcpynW(pLogonIPCUserID->wszUsername, pwszUsername + i, ARRAYSIZE(pLogonIPCUserID->wszUsername));
|
||
|
fDone = true;
|
||
|
}
|
||
|
else if (pwszUsername[i] == L'@')
|
||
|
{
|
||
|
lstrcpynW(pLogonIPCUserID->wszUsername, pwszUsername, ARRAYSIZE(pLogonIPCUserID->wszUsername));
|
||
|
pLogonIPCUserID->wszDomain[0] = L'\0';
|
||
|
fDone = true;
|
||
|
}
|
||
|
}
|
||
|
if (!fDone)
|
||
|
{
|
||
|
lstrcpyW(pLogonIPCUserID->wszUsername, pwszUsername);
|
||
|
if (pwszDomain != NULL)
|
||
|
{
|
||
|
lstrcpyW(pLogonIPCUserID->wszDomain, pwszDomain);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pLogonIPCUserID->wszDomain[0] = L'\0';
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------------------------------------
|
||
|
// CLogonIPC::SendToLogonService
|
||
|
//
|
||
|
// Arguments: wQueryType = What type of service we are interested in.
|
||
|
// pData = Pointer to the data.
|
||
|
// wDataSize = Size of the data.
|
||
|
// fBlock = Block message pump or not.
|
||
|
//
|
||
|
// Returns: bool = Success or failure.
|
||
|
//
|
||
|
// Purpose: Takes the package data and sends the message to the logon
|
||
|
// service provider and receives the result. The logon service
|
||
|
// provider started this process and reads this process' memory
|
||
|
// directly (like a debugger would).
|
||
|
//
|
||
|
// This function should block the message pump because if it
|
||
|
// processes another state change message while waiting for a
|
||
|
// response it could destroy data.
|
||
|
//
|
||
|
// History: 1999-08-20 vtan created
|
||
|
// 2001-06-22 vtan changed to SendMessageTimeout
|
||
|
// 2001-06-28 vtan added block parameter
|
||
|
// --------------------------------------------------------------------------
|
||
|
|
||
|
bool CLogonIPC::SendToLogonService (WORD wQueryType, void *pData, WORD wDataSize, bool fBlock)
|
||
|
|
||
|
{
|
||
|
bool fResult;
|
||
|
|
||
|
fResult = IsLogonServiceAvailable();
|
||
|
if (fResult)
|
||
|
{
|
||
|
DWORD_PTR dwResult;
|
||
|
|
||
|
reinterpret_cast<LOGONIPC*>(pData)->fResult = false;
|
||
|
|
||
|
// WARNING: Danger Will Robinson.
|
||
|
|
||
|
// Do NOT change INT_MAX to INFINITE. INT_MAX is a SIGNED number.
|
||
|
// INFINITE is an UNSIGNED number. Despite the SDK and prototype
|
||
|
// of SendMessageTimeout this timeout value is a SIGNED number.
|
||
|
// Passing in an unsigned number causes the timeout to be
|
||
|
// ignored and the function returns with a timeout.
|
||
|
|
||
|
(LRESULT)SendMessageTimeout(_hwndLogonService,
|
||
|
WM_LOGONSERVICEREQUEST,
|
||
|
MAKEWPARAM(wDataSize, wQueryType),
|
||
|
reinterpret_cast<LPARAM>(pData),
|
||
|
fBlock ? SMTO_BLOCK : SMTO_NORMAL,
|
||
|
INT_MAX, // See above warning.
|
||
|
&dwResult);
|
||
|
fResult = (reinterpret_cast<LOGONIPC*>(pData)->fResult != FALSE);
|
||
|
}
|
||
|
return(fResult);
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------------------------------------
|
||
|
// CLogonIPC::PostToLogonService
|
||
|
//
|
||
|
// Arguments: wQueryType = What type of service we are interested in.
|
||
|
// pData = Pointer to the data.
|
||
|
// wDataSize = Size of the data.
|
||
|
//
|
||
|
// Returns: <none>
|
||
|
//
|
||
|
// Purpose: Takes the package data and posts the message to the logon
|
||
|
// service provider and receives the result. The logon service
|
||
|
// provider started this process and reads this process' memory
|
||
|
// directly (like a debugger would).
|
||
|
//
|
||
|
// History: 1999-11-26 vtan created
|
||
|
// --------------------------------------------------------------------------
|
||
|
|
||
|
void CLogonIPC::PostToLogonService (WORD wQueryType, void *pData, WORD wDataSize)
|
||
|
|
||
|
{
|
||
|
if (IsLogonServiceAvailable())
|
||
|
{
|
||
|
TBOOL(PostMessage(_hwndLogonService, WM_LOGONSERVICEREQUEST, MAKEWPARAM(wDataSize, wQueryType), reinterpret_cast<LPARAM>(pData)));
|
||
|
}
|
||
|
}
|
||
|
|