Are there Windows API functions that allows reading what the current password policy is? For instance, minimum length, complexity etc.
If not reading, is there a wa
Eugene's answer is helpful, but not quite what I needed. The password complexity filter can actually be customized, and what would be good would be a way of asking Windows, does this password meet the requirements?
It took me a while to locate it, but the function is NetValidatePasswordPolicy
. The MSDN docs for this function are awful; check out this MSDN blog entry instead.
Querying ActiveDirectory only works for computers joined to a domain; and where the user has the ability to query the domain controller (which is something that can be un-granted).
@NicholasWilson's answer of using NetValidatePasswordPolicy
is a good one; as it can do a lot of heavy lifting for you. It can even perform password quality checks that you would have to re-implement yourself. But NetValidatePasswordPolicy
does fail as examining your custom password history when you use salted hashes to store passwords (e.g. BCrypt or Scrypt).
But the real question is how to query for the current machine's (even an non-domain joined machine's) password policy. You can query that using:
NetUserModalsGet
struct USER_MODALS_INFO_0
{
DWORD usrmod0_min_passwd_len;
DWORD usrmod0_max_passwd_age;
DWORD usrmod0_min_passwd_age
DWORD usrmod0_force_logoff;
DWORD usrmod0_password_hist_len;
}
PUSER_MODALS_INFO_0 = ^USER_MODALS_INFO_0;
PUSER_MODALS_INFO_0 info0;
NET_API_STATUS res = NetUserModalsGet(nil, 0, out info0);
if (res <> NERR_Success)
RaiseWin32Error(res);
try
//Specifies the minimum allowable password length.
//Valid values for this element are zero through PWLEN.
Log(info0.usrmod0_min_passwd_len);
//Specifies, in seconds, the maximum allowable password age.
//A value of TIMEQ_FOREVER indicates that the password never expires.
//The minimum valid value for this element is ONE_DAY.
//The value specified must be greater than or equal to the value for the usrmod0_min_passwd_age member.
Log(info0.usrmod0_max_passwd_age);
//Specifies the minimum number of seconds that can elapse between the time
//a password changes and when it can be changed again.
//A value of zero indicates that no delay is required between password updates.
//The value specified must be less than or equal to the value for the usrmod0_max_passwd_age member.
Log(info0.usrmod0_min_passwd_age);
//Specifies, in seconds, the amount of time between the end of the valid
// logon time and the time when the user is forced to log off the network.
//A value of TIMEQ_FOREVER indicates that the user is never forced to log off.
//A value of zero indicates that the user will be forced to log off immediately when the valid logon time expires.
Log(info0.usrmod0_force_logoff);
//Specifies the length of password hi'+'story maintained.
//A new password cannot match any of the previous usrmod0_password_hist_len passwords.
//Valid values for this element are zero through DEF_MAX_PWHIST
Log(info0.usrmod0_password_hist_len);
finally
NetApiBufferFree(info0);
end;
See Security Watch Windows Domain Password Policies. You can hit AD using ADSI or its wrappers. I found a VBScript sample. You can translate it to any language you want:
Sub ListPasswordPolicyInfo( strDomain )
Dim objComputer
Set objComputer = GetObject("WinNT://" & strDomain )
WScript.Echo "MinPasswordAge: " & ((objComputer.MinPasswordAge) / 86400)
WScript.Echo "MinPasswordLength: " & objComputer.MinPasswordLength
WScript.Echo "PasswordHistoryLength: " & objComputer.PasswordHistoryLength
WScript.Echo "AutoUnlockInterval: " & objComputer.AutoUnlockInterval
WScript.Echo "LockOutObservationInterval: " & objComputer.LockOutObservationInterval
End Sub
Dim strDomain
Do
strDomain = inputbox( "Please enter a domainname", "Input" )
Loop until strDomain <> ""
ListPasswordPolicyInfo( strDomain )
As a bonus, check out LDAP Admin. It's an open source LDAP directory editor, which you can use to test things, and also checkout the code written in Delphi.