SmartCardCredentialsProvider.dll UI不接受用户输入

时间:2018-04-16 17:28:33

标签: winapi mfc windows-authentication windows-security

我的公司正在为Windows中的SmartCard安全设置进行编程。但是,当我们更新到Fall Creators时,我们遇到了麻烦,开发人员可以通过不将父窗口传递给CredUIPromptForWindowsCredentialsW()函数(desktop / root / NULL)来缓解这种情况。如果我们通过父窗口,则会导致无法访问智能卡登录对话框,如弹出窗口,但是当您单击它时,会听到窗口的默认蜂鸣声,您无法键入任何内容。我看过使用Spy ++并且它声明没有子窗口干扰,但有些消息进入Spy ++可以看到的窗口(WM_SETCURSORWM_MOUSEMOVEWM_LBUTTONDOWNWM_LBUTTONUP以及一堆具有各种参数的注册SHELLHOOK

如果有所不同,应用程序是使用MFC MBCS框架编写的。

我尝试过的事情是:

  1. 显示父窗口(当前隐藏)。这有时在我使用::ShowWindow(m_Parent, SW_SHOW);时有效,但在我使用::SetWindowPos(m_Parent, NULL, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
  2. 时无效
  3. 我试图绕过消息和线程创建函数,试图记录正在发生的事情,但我似乎没有得到任何信息。
  4. 我真的在摸不着头脑。为什么智能卡登录窗口无法获得焦点?有什么可能干扰这个?我们需要停止使用此解决方法,并实际让智能卡登录具有父窗口。

    我在Debug Output窗口中找到的一些东西是:

    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.
    

    虽然这些是父级是根(桌面)或我们的窗口时出现的,所以我不确定它们是否有意义。

    修改

    以下是用于打开智能卡对话框的代码(或多或少):

    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 个答案:

答案 0 :(得分:0)

这个问题的解决方法,我认为最好不设置父级,是轮询安全性对话框,一旦它可见但仍未启用,则启用它。

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什么时候会修复它。