Пользовательский интерфейс SmartCardCredentialsProvider.dll не принимает пользовательский ввод
Моя компания занимается программированием для настройки безопасности SmartCard в Windows. Однако мы попали в ловушку, когда обновились до Fall Creators, которые разработчик смог смягчить, не передав родительское окно в CredUIPromptForWindowsCredentialsW()
функция (рабочий стол / root / NULL
). Если мы пропустим родительское окно, это приведет к тому, что диалоговое окно "Вход в смарт-карту" станет недоступным, так как всплывающее окно откроется, но при нажатии на него будет слышен звуковой сигнал окна по умолчанию, и вы ничего не сможете набрать. Я посмотрел с помощью Spy++, и он утверждает, что нет никакого дочернего окна, которое мешает, но есть сообщения, попадающие в окно, которое может видеть Spy++ (WM_SETCURSOR
, WM_MOUSEMOVE
, WM_LBUTTONDOWN
, WM_LBUTTONUP
и куча зарегистрированных SHELLHOOK
с различными параметрами).
Приложение написано с использованием инфраструктуры MFC MBCS, если это имеет значение.
Вот что я пробовал:
- Отображение родительского окна (в данный момент скрыто). Это иногда работает, когда я использую
::ShowWindow(m_Parent, SW_SHOW);
но никогда не работает, когда я использую::SetWindowPos(m_Parent, NULL, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
- Я пытался обойти функции создания сообщений и потоков, пытаясь записать, что происходит, но, похоже, я не получил никакой информации.
Я действительно почесал голову от этого. Почему окно входа в систему Smart Card не получает фокус? Что может мешать этому? Нам нужно прекратить использовать этот обходной путь и фактически получить логин смарт-карты, чтобы иметь родительское окно.
Некоторые вещи, которые я нашел в окне "Отладочный вывод":
Exception thrown at 0x763008F2 in app.exe: Microsoft C++ exception: errorlib::specific_error_exception<hresult_error::tag> at memory location 0x3B74F824.
Exception thrown at 0x763008F2 in app.exe: Microsoft C++ exception: errorlib::specific_error_exception<hresult_error::tag> at memory location 0x3B74F824.
Exception thrown at 0x763008F2 in app.exe: Microsoft C++ exception: errorlib::specific_error_exception<hresult_error::tag> at memory location 0x3B74F8E4.
Exception thrown at 0x763008F2 in app.exe: Microsoft C++ exception: errorlib::specific_error_exception<hresult_error::tag> at memory location 0x3B74F8C8.
onecoreuap\ds\security\fido\credprov\dll\fidoscenariocredui.cpp(44)\fidocredprov.dll!3C8CD0D9: (caller: 3C8CB529) ReturnHr(1) tid(5488) 80070057 The parameter is incorrect.
Msg:[InvalidFlags 32]
onecoreuap\ds\security\fido\credprov\dll\fidoprovider.cpp(62)\fidocredprov.dll!3C8CB540: (caller: 27886879) ReturnHr(2) tid(5488) 80070057 The parameter is incorrect.
onecore\ds\security\biometrics\credprov\provider_v2\bioprovider.cpp(99)\BioCredProv.dll!3CDC9620: (caller: 27886879) ReturnHr(1) tid(5488) 80098003 CallContext:[\SetUsageScenario]
onecore\ds\security\biometrics\credprov\provider_v2\bioprovider.cpp(206)\BioCredProv.dll!3CDC9117: (caller: 27886ECF) ReturnHr(2) tid(5488) 80004001 Not implemented
CallContext:[\UnAdvise]
onecoreuap\shell\auth\credprov2fahelper\dll\credprov2fahelper.cpp(80)\CredProv2faHelper.dll!2B0F63E5: (caller: 278870A4) ReturnHr(1) tid(5488) 800704EC This program is blocked by group policy. For more information, contact your system administrator.
Msg:[Device unlock policy not configured]
onecore\ds\security\ngc\utils\common\lib\sidutils.cpp(786)\ngccredprov.dll!3CE59F69: (caller: 3CE58CA0) ReturnHr(1) tid(5488) 80070057 The parameter is incorrect.
Exception thrown at 0x763008F2 (KernelBase.dll) in app.exe: 0x0000071A: The remote procedure call was canceled, or if a call time-out was specified, the call timed out.
Exception thrown at 0x763008F2 (KernelBase.dll) in app.exe: 0x0000071A: The remote procedure call was canceled, or if a call time-out was specified, the call timed out.
Exception thrown at 0x763008F2 (KernelBase.dll) in app.exe: 0x0000071A: The remote procedure call was canceled, or if a call time-out was specified, the call timed out.
Exception thrown at 0x763008F2 in app.exe: Microsoft C++ exception: unsigned long at memory location 0x3B74F194.
Хотя они появляются, когда родителем является root (рабочий стол) или наше окно, поэтому я не уверен, что они что-то значат.
РЕДАКТИРОВАТЬ
Вот код (более или менее), который используется для вызова диалогового окна Smart Card:
CREDUI_INFOW credUIInfo;
memset(&credUIInfo, 0, sizeof(credUIInfo));
credUIInfo.cbSize = sizeof(credUIInfo);
credUIInfo.hwndParent = m_Parent;
credUIInfo.pszCaptionText = L"Smart Card Login";
ULONG ulAuthPackageID = 0;
HANDLE hLSA = NULL;
DWORD dwErr = LsaNtStatusToWinError(LsaConnectUntrusted(&hLSA));
if (dwErr == ERROR_SUCCESS) {
LSA_STRING lsaszAuthPackageName;
SizeTToUShort(strlen("Negotiate"), &lsaszAuthPackageName.Length);
lsaszAuthPackageName.MaximumLength = lsaszAuthPackageName.Length + sizeof(CHAR);
lsaszAuthPackageName.Buffer = (PCHAR)"Negotiate";
dwErr = LsaNtStatusToWinError(LsaLookupAuthenticationPackage(hLSA, &lsaszAuthPackageName, &ulAuthPackageID));
}
// Disconnect from the LSA server:
if (hLSA) {LsaDeregisterLogonProcess(hLSA);}
KERB_CERTIFICATE_LOGON credFilter;
memset(&credFilter, 0, sizeof(credFilter));
credFilter.MessageType = KerbCertificateLogon; // (indicates an interactive smart card certificate login)
LPVOID pCredBuffer = NULL;
DWORD dwCredLen = 0;
dwErr = CredUIPromptForWindowsCredentialsW(&credUIInfo, dwErr, &ulAuthPackageID, &credFilter, sizeof(credFilter), &pCredBuffer, &dwCredLen, NULL, CREDUIWIN_IN_CRED_ONLY);
РЕДАКТИРОВАТЬ 2
Похоже, что диалог отключен в соответствии с Spy++. Написание быстрого небольшого приложения, которое с учетом любого дескриптора окна включит окно, связанное с этим дескриптором, вызвав EnableWindow()
фактически включит окно. Почему это так? Почему окно будет отключено?
1 ответ
Обойти эту проблему, которая, на мой взгляд, лучше, чем не устанавливать родителя, - опросить диалоговое окно безопасности, и когда оно станет видимым, но оно все еще не включено, включите его.
constexpr UINT_PTR enable_window_id = 0;
::SetTimer(m_Parent, enable_window_id, 100, [](HWND hwnd, UINT /*msg*/, UINT_PTR id, DWORD /*dwTime*/)
{
if (HWND hChild = ::FindWindow(_T("Credential Dialog Xaml Host"), nullptr))
{
if (::IsWindowVisible(hChild) && !::IsWindowEnabled(hChild))
{
::EnableWindow(hChild, TRUE);
::KillTimer(hwnd, id);
}
}
});
//...
// CredUIPromptForWindowsCredentials(...) call
//...
// If MS ever fixes this problem, will need to kill this timer manually
::KillTimer(m_Parent, enable_window_id);
Я лично думаю, что это действительно глупо, но кто знает, когда MS это исправит.