首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用CredUIPromptForWindowsCredentials验证凭据

如何使用CredUIPromptForWindowsCredentials验证凭据
EN

Stack Overflow用户
提问于 2018-10-12 20:02:25
回答 2查看 805关注 0票数 1

我不知道为什么我不能用CredUnPackAuthenticationBufferW解压缩CredUIPromptForWindowsCredentials中使用的身份验证缓冲区,我总是得到ERROR_INSUFFICIENT_BUFFER错误。我会感谢你的帮助。

代码语言:javascript
复制
std::wstring caption = L"Caption";
std::wstring msg= L"Msg";
CREDUI_INFOW credui = {};
credui.cbSize = sizeof(credui);
credui.hwndParent = nullptr;
credui.pszMessageText = msg.c_str();
credui.pszCaptionText = caption.c_str();
credui.hbmBanner = nullptr;

ULONG  authPackage = 0;
LPVOID outCredBuffer = nullptr;
ULONG  outCredSize = 0;
BOOL   save = false;

LPWSTR pszUserName = nullptr;
DWORD pcchlMaxUserName = 0;
LPWSTR pszDomainName = nullptr;
DWORD pcchMaxDomainName = 0;
LPWSTR pszPassword = nullptr;
DWORD pcchMaxPassword = 0;

DWORD result = CredUIPromptForWindowsCredentialsW(&credui,
                                                0,
                                                &authPackage,
                                                nullptr,
                                                0,
                                                &outCredBuffer,
                                                &outCredSize,
                                                &save,
                                                CREDUIWIN_ENUMERATE_ADMINS);


std::cout <<CredUnPackAuthenticationBufferW(CRED_PACK_PROTECTED_CREDENTIALS
                                ,outCredBuffer
                                ,outCredSize
                                ,pszUserName
                                ,&pcchlMaxUserName
                                ,pszDomainName
                                ,&pcchMaxDomainName
                                ,pszPassword
                                ,&pcchMaxPassword) << std::endl;

std::cout << GetLastError() << std::endl; // out put 122 == ERROR_INSUFFICIENT_BUFFER 
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-10-12 23:13:47

这是典型的winapi模式- api必须在内存缓冲区中返回一些信息。而是自己分配缓冲区--它要求调用方分配缓冲区。因此,调用方必须自行分配缓冲区,并将其指针和大小传递给api。api检查缓冲区大小--如果缓冲区的填充信息足够大,则返回ERROR_INSUFFICIENT_BUFFER (假设没有其他错误)或有时返回ERROR_MORE_DATA。哪个具体的错误拒绝了ERROR_INSUFFICIENT_BUFFERERROR_MORE_DATA通常直接记录的api调用。这两个错误的不同之处在于:ERROR_INSUFFICIENT_BUFFER --意味着没有任何信息被填充到缓冲区中,当ERROR_MORE_DATA意味着返回一些数据时,但是不完整。api通过一些out参数返回给用户,在这种情况下需要缓冲区大小。这通常是通过相同的inout参数-指向DWORD的指针来完成的。在输入中指定用户分配的缓冲区的大小,在输出中指定所需的缓冲区大小或返回数据的大小。

通常需要哪些缓冲区大小--开始时未知。因此,我们首先需要或调用具有0大小缓冲区的api,或者分配一些,据称是足够的缓冲区大小。如果缓冲区不够-重新分配或扩展它并再次调用api。对于某些api (如CredUnPackAuthenticationBufferW),所需的输出缓冲区不会随时间而变化(如果输入参数没有改变),但通常的输出缓冲区大小在调用之间可能会发生变化--即使第二次调用返回缓冲区大小的调用也会因缓冲区大小错误而失败(因为返回的数据可能在调用之间增长)。在这种情况下,需要在do/while(error == ERROR_INSUFFICIENT_BUFFER/ERROR_MORE_DATA)循环中调用api。但是,即使在输出缓冲区不随时间变化的情况下,我们也可以更好地在其中使用单个api调用来执行is循环,而不是使用2个api调用。

对于具体的案例代码,如下所示

代码语言:javascript
复制
ULONG cred()
{
    CREDUI_INFO ci = { sizeof(ci) };
    BOOL bSave = FALSE;

    PVOID pvOutAuthBuffer;
    ULONG ulOutAuthBufferSize;
    ULONG ulAuthPackage = 0;
    ULONG dwError = CredUIPromptForWindowsCredentials(
        &ci, NOERROR, &ulAuthPackage, 0, 0, 
        &pvOutAuthBuffer, &ulOutAuthBufferSize, 
        &bSave, CREDUIWIN_ENUMERATE_ADMINS );

    if (dwError == NOERROR)
    {
        ULONG cchUserName = 0;
        ULONG cchPassword = 0;
        ULONG cchDomain = 0;

        static volatile UCHAR guz = 0;

        PWSTR stack = (PWSTR)alloca(guz);
        PWSTR szUserName = 0, szPassword = 0, szDomainName = 0;

        ULONG cchNeed, cchAllocated = 0;

        do 
        {
            if (cchAllocated < (cchNeed = cchUserName + cchPassword + cchDomain))
            {
                szUserName = (PWSTR)alloca((cchNeed - cchAllocated) * sizeof(WCHAR));
                cchAllocated = (ULONG)(stack - szUserName);
                szPassword = szUserName + cchUserName;
                szDomainName = szPassword + cchPassword;
            }

            dwError = CredUnPackAuthenticationBuffer(
                CRED_PACK_PROTECTED_CREDENTIALS, 
                pvOutAuthBuffer, ulOutAuthBufferSize, 
                szUserName, &cchUserName, 
                szDomainName, &cchDomain, 
                szPassword, &cchPassword)
                ? NOERROR : GetLastError();

            if (dwError == NOERROR)
            {
                DbgPrint("%S@%S %S\n", szDomainName, szUserName, szPassword);
                break;
            }

        } while (dwError == ERROR_INSUFFICIENT_BUFFER);

        CoTaskMemFree(pvOutAuthBuffer);
    }

    return dwError;
}
票数 2
EN

Stack Overflow用户

发布于 2018-10-13 13:23:07

@RbMm -你说得对!我用LogonUser测试了它,它运行得很好。谢谢。为了找到一个现成的解决方案,我得到了这个:

代码语言:javascript
复制
bool Authenticate_ADMIN_User(std::wstring caption, std::wstring msg, int maxReAsks = 0)
{
    CREDUI_INFOW credui   = {};
    credui.cbSize         = sizeof(credui);
    credui.hwndParent     = nullptr;
    credui.pszMessageText = msg.c_str();
    credui.pszCaptionText = caption.c_str();
    credui.hbmBanner      = nullptr;

    ULONG  authPackage   = 0,
           outCredSize   = 0;
    LPVOID outCredBuffer = nullptr;
    BOOL   save          = false;

    DWORD err   = 0;
    int   tries = 0;

    bool reAsk = false;

    do
    {
      tries++;

      if(CredUIPromptForWindowsCredentialsW(&credui,
                                         err,
                                         &authPackage,
                                         nullptr,
                                         0,
                                         &outCredBuffer,
                                         &outCredSize,
                                         &save,
                                         CREDUIWIN_ENUMERATE_ADMINS)

              != ERROR_SUCCESS)
          return false;


      ULONG cchUserName = 0;
      ULONG cchPassword = 0;
      ULONG cchDomain   = 0;
      ULONG cchNeed, cchAllocated = 0;

      static volatile UCHAR guz = 0;

      PWSTR stack = (PWSTR)alloca(guz);
      PWSTR szUserName = nullptr, szPassword = nullptr, szDomainName = nullptr;

      BOOL ret;

      do{
          if (cchAllocated < (cchNeed = cchUserName + cchPassword + cchDomain))
          {
              szUserName = (PWSTR)alloca((cchNeed - cchAllocated) * sizeof(WCHAR));
              cchAllocated = (ULONG)(stack - szUserName);
              szPassword = szUserName + cchUserName;
              szDomainName = szPassword + cchPassword;
          }

          ret = CredUnPackAuthenticationBuffer(
              CRED_PACK_PROTECTED_CREDENTIALS , outCredBuffer, outCredSize, szUserName, &cchUserName,
              szDomainName, &cchDomain, szPassword,
              &cchPassword);

      }while(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER);


        SecureZeroMemory(outCredBuffer, outCredSize);
        CoTaskMemFree(outCredBuffer);

        HANDLE handle = nullptr;

        if (LogonUser(szUserName, 
                      szDomainName,
                      szPassword,
                      LOGON32_LOGON_INTERACTIVE, 
                      LOGON32_PROVIDER_DEFAULT,
                      &handle)) 
        {

          CloseHandle(handle);
          return true;
        }

        else
        {
          err = ERROR_LOGON_FAILURE;
          reAsk = true;
        }


    }while(reAsk && tries < maxReAsks);

    return false;
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52786299

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档