How to check password complexity using NetValidatePasswordPolicy

The NetValidatePasswordPolicy function allows an application to verify that passwords meet the complexity requirement.
Here is an important remark from Microsoft :
“The NetValidatePasswordPolicy function does not validate passwords in Active Directory accounts and cannot be used for this purpose. The only policy that this function checks a password against in Active Directory accounts is the password complexity (the password strength).”

The following code checks if the password meets complexity requirement using NetValidatePasswordPolicy:

#include <Windows.h>
#include <Lm.h>
#include <Dsgetdc.h>
#include <stdio.h>

WCHAR *DisplayErrorText(DWORD dwLastError)
{
    HMODULE hModule = NULL;
    LPWSTR MessageBuffer = NULL;
    DWORD dwBufferLength;

    DWORD dwFormatFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER |
        FORMAT_MESSAGE_IGNORE_INSERTS |
        FORMAT_MESSAGE_FROM_SYSTEM ;

    if(dwLastError >= NERR_BASE && dwLastError <= MAX_NERR) {
        hModule = LoadLibraryEx(
            TEXT("netmsg.dll"),
            NULL,
            LOAD_LIBRARY_AS_DATAFILE
            );

        if(hModule != NULL)
            dwFormatFlags |= FORMAT_MESSAGE_FROM_HMODULE;
    }

    FormatMessageW(
        dwFormatFlags,
        hModule,
        dwLastError,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPWSTR) &MessageBuffer,
        0,
        NULL
        );

    if(hModule != NULL)
        FreeLibrary(hModule);

	return MessageBuffer;
}


int wmain(int argc, wchar_t * argv[])
{
      NET_API_STATUS status;
      NET_VALIDATE_PASSWORD_CHANGE_INPUT_ARG InputArg = {0};
	  DWORD res = 0;
	  wchar_t* wzServer = NULL;
      NET_VALIDATE_OUTPUT_ARG* pOutputArg = NULL;

	  if(argc < 2)
	  {
		  wprintf(L"Usage: MyNetValidatePasswordPolicy password\r\n");
		  return -1;
	  }

	  PDOMAIN_CONTROLLER_INFO  DcInfo;// Get address of nearest DC as cached by OS at boot time.
      if (!DsGetDcName(NULL, NULL, NULL, NULL,
                    DS_DIRECTORY_SERVICE_REQUIRED | DS_RETURN_FLAT_NAME,
                    &DcInfo))
      {
		  wzServer = DcInfo->DomainControllerName;
	  }
	  else
		  wzServer = _wgetenv(L"LOGONSERVER");

      InputArg.ClearPassword = argv[1];
      InputArg.PasswordMatch = TRUE;
      status = NetValidatePasswordPolicy(wzServer, NULL, NetValidatePasswordChange, &InputArg, (void**)&pOutputArg);
	  if(status != NERR_Success)
	  {
		  wprintf(L"Error NetValidatePasswordPolicy %s\r\n", DisplayErrorText(status));
	  }
	  else
	  {
		  if(pOutputArg->ValidationStatus == 0)
			  wprintf(L"Password validated for a password change operation\r\n");
		  else
			  wprintf(L"Password validation failed for a password change operation: %s\r\n", DisplayErrorText(pOutputArg->ValidationStatus));
	  }
      NetValidatePasswordPolicyFree((void**)&pOutputArg);
	  return 0;
} 

How to test if user logged in with cached credentials using LsaGetLogonSessionData function in C++

In some case it will be useful to check if users are logged in with cached credentials (for example to notify users when they have been using cached credentials to log into their laptop for too long).

The following code gets user’s last logon information with the use of LSA (Local Security Authority) API LsaGetLogonSessionData.
When cached credentials are used the LOGON_CACHED_ACCOUNT flag is set (pLogonSessionData->UserFlags & LOGON_CACHED_ACCOUNT)

#include "stdafx.h"
#include <Windows.h>
#include <Ntsecapi.h>
#include <ntstatus.h> 
#include <malloc.h>
#include <strsafe.h>

void PrintLogonType (SECURITY_LOGON_TYPE type)
{
    if (type < Interactive || type > CachedUnlock)
        _tprintf (TEXT("LogonType: UndefinedLogonType\n"));
    else {
        static LPTSTR szTypes[] = {
            TEXT("Interactive"),
            TEXT("Network"), 
            TEXT("Batch"), 
            TEXT("Service"), 
            TEXT("Proxy"),
            TEXT("Unlock"), 
            TEXT("NetworkCleartext"),
            TEXT("NewCredentials"), 
            TEXT("RemoteInteractive"),
            TEXT("CachedInteractive"),
            TEXT("CachedRemoteInteractive"),
            TEXT("CachedUnlock")
        };
        _tprintf (TEXT("LogonType: %s\n"), szTypes[(int)type-Interactive]);
    }
}


void PrintUnicodeString (LPCTSTR pszPrefix, LSA_UNICODE_STRING lsaString)
{
    if (lsaString.MaximumLength >= lsaString.Length + sizeof(WCHAR) &&
        lsaString.Buffer[lsaString.Length/sizeof(WCHAR)] == L'\0')
        _tprintf (TEXT("%s: %ls\n"), pszPrefix, lsaString.Buffer);
    else if (lsaString.Length <= STRSAFE_MAX_CCH * sizeof(TCHAR)) {
        LPWSTR sz = (LPWSTR) _alloca (lsaString.Length + sizeof(WCHAR));
        StringCbCopyNW (sz, lsaString.Length + sizeof(WCHAR), lsaString.Buffer, lsaString.Length);
        _tprintf (TEXT("%s: %ls\n"), pszPrefix, sz);
    }
}

int _tmain(int argc, _TCHAR* argv[])
{
    HANDLE hThread = NULL;
    DWORD dwSize;
    TOKEN_STATISTICS ts;
	LUID luid;

    if(!OpenProcessToken (GetCurrentProcess(), TOKEN_QUERY, &hThread))
	{
		wprintf(L"Error OpenProcessToken rc=0x%.8X\r\n", GetLastError());
		return -1;
	}
	dwSize = sizeof(TOKEN_STATISTICS);
    if(!GetTokenInformation (hThread, TokenStatistics, &ts, sizeof(TOKEN_STATISTICS), &dwSize))
	{
		wprintf(L"Error GetTokenInformation rc=0x%.8X\r\n", GetLastError());
		if (hThread)
            CloseHandle (hThread);
		return -1;
	}
    luid = ts.AuthenticationId;
    if (hThread)
        CloseHandle (hThread);
 
    PSECURITY_LOGON_SESSION_DATA pLogonSessionData = NULL;
    NTSTATUS ntStatus = LsaGetLogonSessionData (&luid, &pLogonSessionData);
    if (ntStatus != STATUS_SUCCESS) {
		wprintf(L"Error LsaGetLogonSessionData rc=0x%.8X\r\n", ntStatus);
		return -1;
	}

    if (pLogonSessionData->UserName.Length)
        PrintUnicodeString (TEXT("UserName"), pLogonSessionData->UserName);
    if (pLogonSessionData->LogonDomain.Length)
        PrintUnicodeString (TEXT("LogonDomain"), pLogonSessionData->LogonDomain);
    if (pLogonSessionData->AuthenticationPackage.Length)
        PrintUnicodeString (TEXT("AuthenticationPackage"), pLogonSessionData->AuthenticationPackage);
    PrintLogonType ((SECURITY_LOGON_TYPE)pLogonSessionData->LogonType);
    _tprintf (TEXT("Session: %d\n"), pLogonSessionData->Session);

    if (pLogonSessionData->LogonServer.Length)
        PrintUnicodeString (TEXT("LogonServer"), pLogonSessionData->LogonServer);
    if (pLogonSessionData->DnsDomainName.Length)
        PrintUnicodeString (TEXT("DnsDomainName"), pLogonSessionData->DnsDomainName);
    if (pLogonSessionData->Upn.Length)
        PrintUnicodeString (TEXT("Upn"), pLogonSessionData->Upn);

	if(pLogonSessionData->UserFlags & LOGON_GUEST) wprintf(L"UserFlags=LOGON_GUEST\r\n");
	if(pLogonSessionData->UserFlags & LOGON_NOENCRYPTION) wprintf(L"UserFlags=LOGON_NOENCRYPTION\r\n");
	if(pLogonSessionData->UserFlags & LOGON_CACHED_ACCOUNT) wprintf(L"UserFlags=LOGON_CACHED_ACCOUNT\r\n");
	if(pLogonSessionData->UserFlags & LOGON_USED_LM_PASSWORD) wprintf(L"UserFlags=LOGON_USED_LM_PASSWORD\r\n");
	if(pLogonSessionData->UserFlags & LOGON_EXTRA_SIDS) wprintf(L"UserFlags=LOGON_EXTRA_SIDS\r\n");
	if(pLogonSessionData->UserFlags & LOGON_SUBAUTH_SESSION_KEY) wprintf(L"UserFlags=LOGON_SUBAUTH_SESSION_KEY\r\n");
	if(pLogonSessionData->UserFlags & LOGON_SERVER_TRUST_ACCOUNT) wprintf(L"UserFlags=LOGON_SERVER_TRUST_ACCOUNT\r\n");
	if(pLogonSessionData->UserFlags & LOGON_NTLMV2_ENABLED) wprintf(L"UserFlags=LOGON_NTLMV2_ENABLED\r\n");
	if(pLogonSessionData->UserFlags & LOGON_RESOURCE_GROUPS) wprintf(L"UserFlags=LOGON_RESOURCE_GROUPS\r\n");
	if(pLogonSessionData->UserFlags & LOGON_PROFILE_PATH_RETURNED) wprintf(L"UserFlags=LOGON_PROFILE_PATH_RETURNED\r\n");
	if(pLogonSessionData->UserFlags & LOGON_NT_V2) wprintf(L"UserFlags=LOGON_NT_V2\r\n");
	if(pLogonSessionData->UserFlags & LOGON_LM_V2) wprintf(L"UserFlags=LOGON_LM_V2\r\n");
	if(pLogonSessionData->UserFlags & LOGON_NTLM_V2) wprintf(L"UserFlags=LOGON_NTLM_V2\r\n");

	if(pLogonSessionData->UserFlags & LOGON_WINLOGON) wprintf(L"UserFlags=LOGON_WINLOGON\r\n");
	if(pLogonSessionData->UserFlags & LOGON_PKINIT) wprintf(L"UserFlags=LOGON_PKINIT\r\n");
	if(pLogonSessionData->UserFlags & LOGON_OPTIMIZED) wprintf(L"UserFlags=LOGON_OPTIMIZED\r\n");
	if(pLogonSessionData->UserFlags & LOGON_NO_OPTIMIZED) wprintf(L"UserFlags=LOGON_NO_OPTIMIZED\r\n");
 
    if (pLogonSessionData)
        LsaFreeReturnBuffer(pLogonSessionData);

	return 0;
}

How to get the group memberships in an access Token in C++ with GetTokenInformation and LookupAccountSid

The following example returns the group memberships in the current process’s access token

#include "stdafx.h"
#include <Windows.h>
#include <Iads.h>
#include <AdsHlp.h>

int _tmain(int argc, _TCHAR* argv[])
{
	DWORD i, dwSize;
	HANDLE hToken;
	PTOKEN_GROUPS pGroupInfo;
	PTOKEN_USER pUserInfo = NULL;
    HRESULT hr;

    hr = CoInitialize(NULL);
    if(SUCCEEDED(hr))
    {
		// Open a handle to the access token for the calling process.
		if (OpenProcessToken (GetCurrentProcess(), TOKEN_QUERY, &hToken))
		{
			dwSize = 0;
			GetTokenInformation (hToken, TokenUser, NULL, dwSize, &dwSize);
			if (pUserInfo = (PTOKEN_USER) GlobalAlloc (GPTR, dwSize))
			{
				// Call GetTokenInformation again to get the group information.
				if (!GetTokenInformation (hToken, TokenUser, pUserInfo, dwSize, &dwSize)) 
				{
					GlobalFree (pUserInfo);
					pUserInfo = NULL;
				}
			}
			dwSize = 0;
			GetTokenInformation (hToken, TokenGroups, NULL, dwSize, &dwSize);
			if (pGroupInfo = (PTOKEN_GROUPS) GlobalAlloc (GPTR, dwSize))
			{
				if (GetTokenInformation (hToken, TokenGroups, pGroupInfo, dwSize, &dwSize)) 
				{
					static WCHAR szName[1024], szDomain[1024];

					for (i=0; i < pGroupInfo->GroupCount; i++)
					{
						if (pGroupInfo->Groups[i].Attributes & SE_GROUP_ENABLED)
						{
							BOOL bEqual = FALSE;
							if (EqualDomainSid (pUserInfo->User.Sid, pGroupInfo->Groups[i].Sid, &bEqual)) 
							{
								if (bEqual)
								{
									DWORD	dwName, dwDomain;
									SID_NAME_USE SidNameUse;
									dwName = 1024;
									dwDomain = 1024;
									if (LookupAccountSid (NULL, pGroupInfo->Groups[i].Sid, szName, &dwName, szDomain, &dwDomain, &SidNameUse))
										wprintf(L"%s\n",szName);
								}
							}
						}
					}
				}
				GlobalFree (pGroupInfo);
			}
			if (pUserInfo != NULL) 
				GlobalFree (pUserInfo);
			
			//Close the access token handle
			CloseHandle (hToken);
		}
	}
    CoUninitialize();
    return 0;
}