// -------------------------------------------------------------------------- // 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: // // Returns: // // Purpose: Initializes the CLogonIPC class. // // History: 1999-08-20 vtan created // -------------------------------------------------------------------------- CLogonIPC::CLogonIPC (void) : _iLogonAttemptCount(0), _hwndLogonService(NULL) { } // -------------------------------------------------------------------------- // CLogonIPC::~CLogonIPC // // Arguments: // // Returns: // // Purpose: Releases any resources used by the CLogonIPC class. // // History: 1999-08-20 vtan created // -------------------------------------------------------------------------- CLogonIPC::~CLogonIPC (void) { } // -------------------------------------------------------------------------- // CLogonIPC::IsLogonServiceAvailable // // Arguments: // // 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(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: // // 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: // // 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: // // 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: // // 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: // // 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: // // 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: // // 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: // // 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(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(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(pData), fBlock ? SMTO_BLOCK : SMTO_NORMAL, INT_MAX, // See above warning. &dwResult); fResult = (reinterpret_cast(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: // // 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(pData))); } }