Browse DevX
Sign up for e-mail newsletters from DevX


Enforce Custom Password Policies in Windows : Page 3

Most people take the easy way out and use the default filter in order to validate passwords. But did you know you can employ authentication modules to customize your password policies to reflect your organization's unique security requirements? Find out how in this article.




Building the Right Environment to Support AI, Machine Learning and Deep Learning

The RegEx Password Filter Sample
Now that you're aware of all the possible pitfalls, it's high time for code action. This section will walk you through the sample provided with this article. I've created a VS7 solution with the PasswordFilterRegEx VC project.

As the Password Filter definition requires, you export three functions. Here's the code for the DEF file included within the sample project:

LIBRARY PasswordFilterRegEx EXPORTS InitializeChangeNotify PasswordChangeNotify PasswordFilter

The PasswordFilterRegEx.cpp contains source code for the exported functions. The implementations of InitializeChangeNotify and PasswordChangeNotify are quite simple:

// Initialization of Password filter. // This implementation just returns TRUE // to let LSA know everything is fine BOOLEAN __stdcall InitializeChangeNotify(void) { WriteToLog("InitializeChangeNotify()"); return TRUE; } // This function is called by LSA when password // was successfully changed. // // This implementation just returns 0 (Success) NTSTATUS __stdcall PasswordChangeNotify( PUNICODE_STRING UserName, ULONG RelativeId, PUNICODE_STRING NewPassword ) { WriteToLog("PasswordChangeNotify()"); return 0; }

The bulk of the work is done in the PasswordFilter function (shown in Listing 1). First, create a zero-terminating copy of a password string and assign it to an STL wstring object (STL is used in conjunction with the boost regex library):

wszPassword = new wchar_t[Password->Length + 1]; if (NULL == wszPassword) { throw E_OUTOFMEMORY; } wcsncpy(wszPassword, Password->Buffer, Password->Length); wszPassword[Password->Length] = 0; WriteToLog("Going to check password"); // Initialize STL string wstrPassword = wszPassword;

Next, the regular expression is instantiated. The sample Password Filter reads the regular expression from the RegEx value of the following registry key:


If the value is not found in registry, the dummy default regular expression ("^(A)$") is used.

Finally, validate the password against the regular expression and return the results to the caller (LSA):

WriteToLog("Going to run match"); // Prepare iterators wstring::const_iterator start = wstrPassword.begin(); wstring::const_iterator end = wstrPassword.end(); match_results<wstring::const_iterator> what; unsigned int flags = match_default; bMatch = regex_match(start, end, what, wrePassword); if (bMatch) { WriteToLog("Password matches specified RegEx"); } else { WriteToLog("Password does NOT match specified RegEx"); } . . . return bMatch;

Just before you return the results to LSA, perform memory clean-up:

// Erase all temporary password data // for security reasons wstrPassword.replace(0, wstrPassword.length(), wstrPassword.length(), (wchar_t)'?'); wstrPassword.erase(); if (NULL != wszPassword) { ZeroMemory(wszPassword, Password->Length); // Assure that there is no compiler optimizations and read random byte // from cleaned password string srand(time(NULL)); wchar_t wch = wszPassword[rand() % Password->Length]; delete [] wszPassword; wszPassword = NULL; } return bMatch;

Thanks for your registration, follow us on our social networks to keep up-to-date