我不知道为什么我不能用CredUnPackAuthenticationBufferW解压缩CredUIPromptForWindowsCredentials中使用的身份验证缓冲区,我总是得到ERROR_INSUFFICIENT_BUFFER错误。我会感谢你的帮助。
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 发布于 2018-10-12 23:13:47
这是典型的winapi模式- api必须在内存缓冲区中返回一些信息。而是自己分配缓冲区--它要求调用方分配缓冲区。因此,调用方必须自行分配缓冲区,并将其指针和大小传递给api。api检查缓冲区大小--如果缓冲区的填充信息足够大,则返回ERROR_INSUFFICIENT_BUFFER (假设没有其他错误)或有时返回ERROR_MORE_DATA。哪个具体的错误拒绝了ERROR_INSUFFICIENT_BUFFER或ERROR_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调用。
对于具体的案例代码,如下所示
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;
}发布于 2018-10-13 13:23:07
@RbMm -你说得对!我用LogonUser测试了它,它运行得很好。谢谢。为了找到一个现成的解决方案,我得到了这个:
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;
}https://stackoverflow.com/questions/52786299
复制相似问题