windows-nt/Source/XPSP1/NT/shell/ext/shgina/logonipc.cpp
2020-09-26 16:20:57 +08:00

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)));
}
}