|
|
// --------------------------------------------------------------------------
// 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; 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.
//
// REVIEW (jeffreys) I don't think that's true.
StringCchCopyNEx(logonIPCCredentials.wszPassword, ARRAYSIZE(logonIPCCredentials.wszPassword), pwszPassword, 127, NULL, NULL, STRSAFE_FILL_BEHIND_NULL); ZeroMemory(pwszPassword, (lstrlen(pwszPassword) + 1) * sizeof(WCHAR));
logonIPCCredentials.iPasswordLength = lstrlen(logonIPCCredentials.wszPassword); logonIPCCredentials.ucPasswordSeed = 0;
passwordString.Buffer = logonIPCCredentials.wszPassword; passwordString.Length = (USHORT)(logonIPCCredentials.iPasswordLength * sizeof(WCHAR)); passwordString.MaximumLength = sizeof(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)
{ LPTSTR psz; LOGONIPC_USERID *pLogonIPCUserID;
pLogonIPCUserID = reinterpret_cast<LOGONIPC_USERID*>(pIdentification);
pLogonIPCUserID->wszUsername[0] = L'\0'; pLogonIPCUserID->wszDomain[0] = L'\0'; psz = StrChrW(pwszUsername, L'\\'); if (psz) { // stuff after the '\' is the username
StringCchCopyW(pLogonIPCUserID->wszUsername, ARRAYSIZE(pLogonIPCUserID->wszUsername), psz + 1);
// stuff before the '\' is the domain name
StringCchCopyNW(pLogonIPCUserID->wszDomain, ARRAYSIZE(pLogonIPCUserID->wszDomain), pwszUsername, psz - pwszUsername); } else { StringCchCopyW(pLogonIPCUserID->wszUsername, ARRAYSIZE(pLogonIPCUserID->wszUsername), pwszUsername); } }
// --------------------------------------------------------------------------
// 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))); } }
|