Hi Team,
I have tried to create a Custom Credential Provider similar to Microsoft PLAP (rasplap.dll). Because the Windows one does not have any other custom input field (OTP/TOTP to perform MFA) apart from the Username and Password to connect to the domain profile by performing the Domain-based authentication after connecting the VPN. I am having a getSerialization Method in dll, which is responsible for doing the login for me after providing the username and password, but I am getting an error message: "The validation information class requested was invalid." I don't know what the issue is. I have even debugged it by printing all the messages, and all the messages are printed in favour, but then I am getting this error when I am trying to sign in from Windows logon. I want to mention the methods I have used in the credential.cpp file. I would be extremely glad if anyone helped me to figure out, where I made the mistake.
The below methods I have used.
static HRESULT _LsaInitString(
__out PSTRING pszDestinationString,
__in PCSTR pszSourceString
)
{
size_t cchLength = lstrlenA(pszSourceString);
USHORT usLength;
HRESULT hr = SizeTToUShort(cchLength, &usLength);
if (SUCCEEDED(hr))
{
pszDestinationString->Buffer = (PCHAR)pszSourceString;
pszDestinationString->Length = usLength;
pszDestinationString->MaximumLength = pszDestinationString->Length + 1;
hr = S_OK;
}
return hr;
}
HRESULT RetrieveNegotiateAuthPackageNew(__out ULONG* pulAuthPackage)
{
HRESULT hr;
HANDLE hLsa;
NTSTATUS status = LsaConnectUntrusted(&hLsa);
if (SUCCEEDED(HRESULT_FROM_NT(status)))
{
LogMessage(L"LsaConnectUntrusted success");
ULONG ulAuthPackage;
LSA_STRING lsaszKerberosName;
_LsaInitString(&lsaszKerberosName, "NTLM");
status = LsaLookupAuthenticationPackage(hLsa, &lsaszKerberosName, &ulAuthPackage);
if (SUCCEEDED(HRESULT_FROM_NT(status)))
{
LogMessage(L"LsaLookupAuthenticationPackage success");
*pulAuthPackage = ulAuthPackage;
hr = S_OK;
}
else
{
LogMessage(L"LsaLookupAuthenticationPackage failed");
hr = HRESULT_FROM_NT(status);
}
wchar_t buffer[128];
swprintf_s(buffer, sizeof(buffer) / sizeof(wchar_t), L"Authentication Package ID: %lu", ulAuthPackage);
LogMessage(buffer);
memset(buffer, 0, sizeof(buffer));
LsaDeregisterLogonProcess(hLsa);
}
else
{
LogMessage(L"LsaConnectUntrusted failed");
hr = HRESULT_FROM_NT(status);
}
return hr;
}
HRESULT CSampleCredential::GetSerialization(
__out CREDENTIAL_PROVIDER_GET_SERIALIZATION_RESPONSE* pcpgsr,
__out CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION* pcpcs,
__deref_out_opt PWSTR* ppwszOptionalStatusText,
__in CREDENTIAL_PROVIDER_STATUS_ICON* pcpsiOptionalStatusIcon
)
{
UNREFERENCED_PARAMETER(ppwszOptionalStatusText);
UNREFERENCED_PARAMETER(pcpsiOptionalStatusIcon);
LogMessage(L"Starting GetSerialization");
WCHAR szCommand[512];
WCHAR* pszVpnName = L"VPN Name";
WCHAR* pszVpnUsername = L"helloworld";
WCHAR* pszVpnPassword = L"abc@123";
// Step 1: Connect to VPN using rasdial
swprintf_s(szCommand, L"rasdial \"%s\" \"%s\" \"%s\"", pszVpnName, pszVpnUsername, pszVpnPassword);
STARTUPINFO si = { sizeof(STARTUPINFO) };
PROCESS_INFORMATION pi = { 0 };
if (!CreateProcess(NULL, szCommand, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) {
LogMessage(L"Failed to start VPN process");
return HRESULT_FROM_WIN32(GetLastError());
}
WaitForSingleObject(pi.hProcess, INFINITE);
DWORD dwExitCode;
if (!GetExitCodeProcess(pi.hProcess, &dwExitCode) || dwExitCode != 0) {
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
LogMessage(L"VPN connection failed");
return HRESULT_FROM_WIN32(ERROR_CONNECTION_UNAVAIL);
}
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
LogMessage(L"VPN connection successful");
HRESULT hr;
if (!_isConnected)
{
LogMessage(L"Not connected. Attempting to establish connection...");
// Attempt to connect before proceeding
IQueryContinueWithStatus* pqcws = nullptr;
if (pqcws != nullptr) {
hr = Connect(pqcws);
if (FAILED(hr))
{
LogMessage(L"Connection failed during GetSerialization.");
return hr;
}
}
}
WCHAR wsz[MAX_COMPUTERNAME_LENGTH + 1];
DWORD cch = ARRAYSIZE(wsz);
if (GetComputerNameW(wsz, &cch))
{
LogMessage(L"Computer Name Extraction Success");
LogMessage(L"Attempting domain authentication...");
DWORD dwAuthFlags = LOGON32_LOGON_NETWORK | LOGON32_PROVIDER_DEFAULT;
HANDLE hToken = NULL;
PWSTR pwzProtectedPassword = L"abc@123";
//LogonUser(_rgFieldStrings[SFI_EDIT_TEXT], L"vpncloud.com", _rgFieldStrings[SFI_PASSWORD], dwAuthFlags, LOGON32_PROVIDER_DEFAULT, &hToken);
if (!LogonUser(_rgFieldStrings[SFI_EDIT_TEXT], L"vpncloud.com", _rgFieldStrings[SFI_PASSWORD], dwAuthFlags, LOGON32_PROVIDER_DEFAULT, &hToken))
{
DWORD dwError = GetLastError();
LogMessage(L"LogonUser failed with error: " + std::to_wstring(dwError));
return HRESULT_FROM_WIN32(dwError);
}
LogMessage(L"Logon User Successfull ..........");
if (hToken != NULL) {
LogMessage(L"Password Protection & Copy Successful");
ULONG ulAuthPackage;
hr = RetrieveNegotiateAuthPackageNew(&ulAuthPackage); // Use NTLM authentication package
if (FAILED(hr))
{
LogMessage(L"FAILED :: RetrieveNTLMAuthPackage failed.");
return hr;
}
LogMessage(L"Authentication Package ulAuthPackage (after method): " + std::to_wstring(ulAuthPackage));
// Prepare the serialization data for NTLM
size_t cbUsername = (wcslen(_rgFieldStrings[SFI_EDIT_TEXT]) + 1) * sizeof(WCHAR);
size_t cbDomain = (wcslen(L"vpncloud.com") + 1) * sizeof(WCHAR);
size_t cbPassword = (wcslen(pwzProtectedPassword) + 1) * sizeof(WCHAR);
size_t cbSerialization = cbUsername + cbDomain + cbPassword;
BYTE* pbSerialization = (BYTE*)CoTaskMemAlloc(cbSerialization);
if (!pbSerialization)
{
LogMessage(L"Memory allocation failed.");
return E_OUTOFMEMORY;
}`your text`
BYTE* pbCurrent = pbSerialization;
memcpy(pbCurrent, _rgFieldStrings[SFI_EDIT_TEXT], cbUsername); // Username
pbCurrent += cbUsername;
memcpy(pbCurrent, L"baarcloud.com", cbDomain); // Domain
pbCurrent += cbDomain;
memcpy(pbCurrent, pwzProtectedPassword, cbPassword); // Password
pcpcs->rgbSerialization = pbSerialization;
pcpcs->cbSerialization = static_cast<ULONG>(cbSerialization);
pcpcs->ulAuthenticationPackage = ulAuthPackage;
pcpcs->clsidCredentialProvider = CLSID_CSample;
*pcpgsr = CPGSR_RETURN_CREDENTIAL_FINISHED;
LogMessage(L"Credentials ready for submission.");
}
}
else
{
DWORD dwErr = GetLastError();
hr = HRESULT_FROM_WIN32(dwErr);
}
return hr;
}