From e6a81456c622d490166b3d2776ab2877f4de1816 Mon Sep 17 00:00:00 2001 From: MutonUfoAI Date: Tue, 17 Oct 2017 11:14:39 +0200 Subject: [PATCH] CP Login screen fixes, last username and Win 10 workaround - if a login has been denied the CP should display - the last username correctly (if enabled) - and Win 10 needed a workaround to refresh the login screen --- pGina/src/CredentialProvider/Credential.cpp | 72 +++++++++++++++++---- pGina/src/CredentialProvider/Credential.h | 4 +- pGina/src/CredentialProvider/Provider.cpp | 18 ++++-- pGina/src/CredentialProvider/Provider.h | 1 + 4 files changed, 75 insertions(+), 20 deletions(-) diff --git a/pGina/src/CredentialProvider/Credential.cpp b/pGina/src/CredentialProvider/Credential.cpp index be8728b2..d0773e5b 100644 --- a/pGina/src/CredentialProvider/Credential.cpp +++ b/pGina/src/CredentialProvider/Credential.cpp @@ -519,19 +519,7 @@ namespace pGina { m_loginResult.Message(L"Plugins did not provide a specific error message"); } - if (pGina::Registry::GetBool(L"LastUsernameEnable", false)) - { - m_fields->fields[m_fields->usernameFieldIdx].fieldStatePair.fieldInteractiveState = CPFIS_NONE; - m_fields->fields[m_fields->passwordFieldIdx].fieldStatePair.fieldInteractiveState = CPFIS_FOCUSED; - } - else - { - ClearZeroAndFreeFields(CPFT_EDIT_TEXT, false); - m_fields->fields[m_fields->usernameFieldIdx].fieldStatePair.fieldInteractiveState = CPFIS_FOCUSED; - m_fields->fields[m_fields->passwordFieldIdx].fieldStatePair.fieldInteractiveState = CPFIS_NONE; - } - ClearZeroAndFreeFields(CPFT_PASSWORD_TEXT, false); - + if (hThread_dialog != NULL) { Credential::Thread_dialog_close(hThread_dialog); @@ -606,10 +594,39 @@ namespace pGina { BlockInput(false); } - ClearZeroAndFreeAnyTextFields(true); + + if (pGina::Registry::GetBool(L"LastUsernameEnable", false)) + { + std::wstring sessionUname = pGina::Registry::GetString( L"LastUsername", L""); + if (!sessionUname.empty()) + { + m_fields->fields[m_fields->usernameFieldIdx].fieldStatePair.fieldInteractiveState = CPFIS_NONE; + m_fields->fields[m_fields->passwordFieldIdx].fieldStatePair.fieldInteractiveState = CPFIS_FOCUSED; + } + else + { + ClearZeroAndFreeFields(CPFT_EDIT_TEXT, false); + m_fields->fields[m_fields->usernameFieldIdx].fieldStatePair.fieldInteractiveState = CPFIS_FOCUSED; + m_fields->fields[m_fields->passwordFieldIdx].fieldStatePair.fieldInteractiveState = CPFIS_NONE; + } + } + else + { + ClearZeroAndFreeFields(CPFT_EDIT_TEXT, false); + m_fields->fields[m_fields->usernameFieldIdx].fieldStatePair.fieldInteractiveState = CPFIS_FOCUSED; + m_fields->fields[m_fields->passwordFieldIdx].fieldStatePair.fieldInteractiveState = CPFIS_NONE; + } + ClearZeroAndFreeFields(CPFT_PASSWORD_TEXT, false); + *pcpgsr = CPGSR_NO_CREDENTIAL_FINISHED; *pcpsiOptionalStatusIcon = CPSI_ERROR; + // Win 10 Workarround to redraw the CP after an error + if (Credential::ISwin10()) + { + Provider::m_redraw = true; + } + return S_FALSE; } @@ -1090,5 +1107,32 @@ namespace pGina WaitForSingleObject(thread, 1000); CloseHandle(thread); } + + // https://stackoverflow.com/questions/36543301/detecting-windows-10-version/36543774#36543774 + BOOL Credential::ISwin10() + { + RTL_OSVERSIONINFOW rovi = { 0 }; + HMODULE hMod = ::GetModuleHandle(L"ntdll.dll"); + if (hMod) + { + Credential::RtlGetVersionPtr fxPtr = (Credential::RtlGetVersionPtr)::GetProcAddress(hMod, "RtlGetVersion"); + if (fxPtr != nullptr) + { + rovi.dwOSVersionInfoSize = sizeof(rovi); + if (fxPtr(&rovi) != 0) + { + rovi.dwMajorVersion = 10; + } + } + FreeLibrary(hMod); + } + + if (rovi.dwMajorVersion == 10) + { + return true; + } + + return false; + } } } diff --git a/pGina/src/CredentialProvider/Credential.h b/pGina/src/CredentialProvider/Credential.h index 441dd7ef..c616e237 100644 --- a/pGina/src/CredentialProvider/Credential.h +++ b/pGina/src/CredentialProvider/Credential.h @@ -77,7 +77,9 @@ namespace pGina DWORD usageFlags, const wchar_t *username, const wchar_t *password); virtual void ServiceStateChanged(bool newState); - + + typedef NTSTATUS(WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW); + BOOL ISwin10(); private: void ClearZeroAndFreeAnyPasswordFields(bool updateUi); void ClearZeroAndFreeAnyTextFields(bool updateUi); diff --git a/pGina/src/CredentialProvider/Provider.cpp b/pGina/src/CredentialProvider/Provider.cpp index 712ac2c6..e0f5fa6b 100644 --- a/pGina/src/CredentialProvider/Provider.cpp +++ b/pGina/src/CredentialProvider/Provider.cpp @@ -49,6 +49,8 @@ namespace pGina { namespace CredProv { + /*static */ bool Provider::m_redraw; + IFACEMETHODIMP Provider::QueryInterface(__in REFIID riid, __deref_out void **ppv) { // And more crazy ass v-table madness, yay COM again! @@ -62,7 +64,13 @@ namespace pGina IFACEMETHODIMP_(ULONG) Provider::AddRef() { - return InterlockedIncrement(&m_referenceCount); + // Win 10 workaround to redraw the CP after an error + if (m_redraw) + { + m_redraw = false; + m_logonUiCallbackEvents->CredentialsChanged(m_logonUiCallbackContext); + } + return InterlockedIncrement(&m_referenceCount); } IFACEMETHODIMP_(ULONG) Provider::Release() @@ -226,16 +234,16 @@ namespace pGina } return result; - } + } IFACEMETHODIMP Provider::Advise(__in ICredentialProviderEvents* pcpe, __in UINT_PTR upAdviseContext) { - // If we already have a callback handle, release our reference to it - UnAdvise(); - // Store what we've been given m_logonUiCallbackEvents = pcpe; m_logonUiCallbackContext = upAdviseContext; + + // If we already have a callback handle, release our reference to it + UnAdvise(); // Up ref count as we hold a pointer to this guy if(m_logonUiCallbackEvents) diff --git a/pGina/src/CredentialProvider/Provider.h b/pGina/src/CredentialProvider/Provider.h index 16369c1c..c6c061c4 100644 --- a/pGina/src/CredentialProvider/Provider.h +++ b/pGina/src/CredentialProvider/Provider.h @@ -61,6 +61,7 @@ namespace pGina virtual void ServiceStateChanged(bool newState); CREDENTIAL_PROVIDER_USAGE_SCENARIO m_usageScenario; + static bool m_redraw; protected: Provider(); __override ~Provider();