Reputation: 117
I am doing a custom wrapped credential provider. In that i need to get the 'new password' field string from change password scenario. As far as I learnt, after user submits from the change password scenario, GetSerialization function in my credential provider is called and there i should be able to get values of the fields that the user has submitted. But I dont know exactly how to get it. I went through all over google and stack overflow but not able to get exactly what i need. Any help would be greatly appreciated.
HRESULT CSampleCredential::GetSerialization(
CREDENTIAL_PROVIDER_GET_SERIALIZATION_RESPONSE* pcpgsr,
CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION* pcpcs,
PWSTR* ppwszOptionalStatusText,
CREDENTIAL_PROVIDER_STATUS_ICON* pcpsiOptionalStatusIcon
)
{
HRESULT hr = E_UNEXPECTED;
if (_pWrappedCredential != NULL)
{
hr = _pWrappedCredential->GetSerialization(pcpgsr, pcpcs, ppwszOptionalStatusText, pcpsiOptionalStatusIcon);
}
logger->log(NORMAL,L"****************GetSerialisation**************\n");
return hr;
}
I'm getting the log "*******Get Serialization******" whenever user submits the logon/unlock form or change password form. There should be some way with that I can get the values of the fields(I'm interested in new password field). Either there should be some field id (so far i could not find one) with which i can access those values, or those values should be stored in some buffer which i should access and get the values or some other thing like that.
Upvotes: 4
Views: 1873
Reputation: 291
If it helps anyone in future; here is how I did it. It's a my figured-out solution with appropriate code snippets from my working V1 (not V2) Wrapped Credential Provider(CP) - as tested on 64-bit Windows 7 and 8.1. (No guarantees on it working on all installations of Windows 7 and 8 though). Built the code using VS 2013 and VS 2010 successfully.
This is a slightly unorthodox way of determining the new password input - in a Change Password(CTRL-ALT-DEL) scenario. But, since my client wanted to track and check for the NEW password's complexity, as the user inputs/types it, it worked really well for me - but only on Windows 7 and 8/8.1; and NOT on Windows 10 - which happens to be a nightmare to implement custom "Change Password" Credential Providers for.
The way I did it, was to : a) check if the "cpus" variable in SetUsageScenario() in CredentialProvider.cpp was equal to CPUS_CHANGE_PASSWORD, and set a global boolean flag to TRUE, if so.
b) then, and this is the key part, in the function SetStringValue(), I kept track of each character input in the NEW password field, using the fieldID(which is the same, for all standard Windows 7/8 installations and default CP's that MS provides) - like this:
CSampleCredential::SetStringValue(
DWORD dwFieldID,
PCWSTR pwz
)
{
string strCurrentFieldData = ws2s(pwz);// this contains the current data , as typed by the user. SO, as the user keeps typing the password, this field will get longer and longer. Perfect!
FILE_LOG(logINFO) << "in SetStringValue() FieldID = " << dwFieldID << " Field value = " << strCurrentFieldData.c_str() ;
eWinVersion ver;
char szVer[64] = { "" };
WCHAR wszFullVersion[255] = { L"" };
bool bSuccess = GetOSVersionString(wszFullVersion, 255, ver, szVer, 64);
if (bSuccess)
{
if (ver == VER_WIN8 || ver == VER_WIN81 )
{
switch (dwFieldID)
{
case PFID_OLDPWD: csOldPassword = strCurrentFieldData;
break;
case PFID_NEWPWD: csNewPassword = strCurrentFieldData;
break;
case PFID_NEWPWDCONF: csNewPasswordConfirmation = strCurrentFieldData;
break;
default:
break;
}
}else
if (ver == VER_WIN7)
{
switch (dwFieldID)
{
case PFID_OLDPWD+1: csOldPassword = strCurrentFieldData;
break;
case PFID_NEWPWD+1: csNewPassword = strCurrentFieldData;
break;
case PFID_NEWPWDCONF+1: csNewPasswordConfirmation = strCurrentFieldData;
break;
default:
break;
}
}
}
}
// and so on...
}
c) then, finally in Get CSampleCredential::Serialization(), I checked the password for complexity and returned the correct CP value, as appropriate - as follows:
//
// Collect the username and password into a serialized credential for the correct usage scenario
// (logon/unlock is what's demonstrated in this sample). LogonUI then passes these credentials
// back to the system to log on.
//
HRESULT CSampleCredential::GetSerialization(
CREDENTIAL_PROVIDER_GET_SERIALIZATION_RESPONSE* pcpgsr,
CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION* pcpcs,
PWSTR* ppwszOptionalStatusText,
CREDENTIAL_PROVIDER_STATUS_ICON* pcpsiOptionalStatusIcon
)
{
FILE_LOG(logINFO) << "In CSampleCredential::GetSerialization";
HRESULT hr = E_UNEXPECTED;
if (_pWrappedCredential != NULL)
{
hr = _pWrappedCredential->GetSerialization(pcpgsr, pcpcs, ppwszOptionalStatusText, pcpsiOptionalStatusIcon);
if (g_bIsChangingPassword)
{
FILE_LOG(logINFO) << "********** In GetSerialization()..... Scenario = Change Password! ";
char buf[256] = { "" };
sprintf_s(buf, 256, "Old password Input = [%s] New password input = [%s] New pwd confirmation inpot = [%s]",
csOldPassword.c_str(), csNewPassword.c_str(), csNewPasswordConfirmation.c_str());
FILE_LOG(logINFO) << buf;
//******************************************
// ************ IMPORTANT*****
// If new password input by user doens't fulfil our complexity requirements, we don't allow password chnge to compelte, by CP
if (!IsPasswordStrong(csNewPassword))
{
HWND hwndOwner = nullptr;
_pCredProvCredentialEvents->OnCreatingWindow(&hwndOwner);
*pcpgsr = CPGSR_NO_CREDENTIAL_NOT_FINISHED;
::MessageBox(hwndOwner,
"The new password you have chosen is not secure enough.\n\rPlease try a more complex password that is:\n\ra) At least 8 characters long\r\nb)contains Upper case AND lower letters\n\rc)and numbers",
"Insufficient Password Strength", 0);
}
//******************************************
}
}
return hr;
}
This is provided to assist anyone who may need help with tracking NEW password fields in a WRAPPED Custom Credential Provider.
Upvotes: 1
Reputation: 183
The wrapped Credential serializes the new password into the CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION structure ready to be returned to Winlogon to present to the LSA. You can deserialize this structure using the CredUnPackAuthenticationBuffer function - and this will reveal what the new password is.
Upvotes: 1