ChangePassword() and Password Complexity Violation Error Codes

This blog post attempts to describe why ChangePassword method of ADSI/System.DirectoryServices throws different error codes for same password string that violates domain password policies.

If you are a seasoned ADSI developer You may have noticed ChangePassword throws two different error codes when the new password violates the Password policy.

One error code is

               ERROR_DS_CONSTRAINT_VIOLATION (0x8007202f)

And the Second one is more descriptive  

NERR_PasswordTooShort (0x800708c5)                 

“The password does not meet the password policy requirements. Check the minimum password length, password complexity and password history requirements. “

In order to understand why the call returns different error codes please refer the remarks section of the MSDN article. The ADSI/S.DS API uses three different methods as described in the MSDN article to change the password. It first tries LDAP over SSL and if it fails to establish a SSL channel it tries Kerberos and Net API calls to change the password. While 0x8007202f is an ADSI LDAP error code, 0x800708c5 is a converted Network Management API error code (0x8c5 = 2245).

So when you see the error code is ERROR_DS_CONSTRAINT_VIOLATION (0x8007202f) it is using LDAP method and when you see  NERR_PasswordTooShort (0x800708c5) it is attempting  NetUserChangePassword for changing the password

Often people complain that the LDAP error code is not so descriptive enough the understand the issue, as it is very generic in nature. But please note that it was provided that way for security reasons

However If you really like to get a consistent, detailed RPC error message we may directly call the Net API. Below is a code snippet which shows how we can make NetUserChangePassword to change the password of an AD user

 #include "stdafx.h"
 
 #ifndef UNICODE
 
 #define UNICODE
 
 #endif
 
 #include <stdio.h>
 
 #include <windows.h>
 
 #include <lm.h>
 
 int wmain(int argc, wchar_t *argv[])
 
 {
 
    DWORD dwError = 0;
 
    NET_API_STATUS nStatus;
 
 //
 
 // Call the NetUserChangePassword function.
 
 //
 
    nStatus = NetUserChangePassword(L"Contoso.local", L"TestUser2",L"Password!", L"Password!2");
 
 //
 
 // If the call succeeds, inform the user.
 
 //
 
 if (nStatus == NERR_Success)
 
       fwprintf(stderr, L"User password has been changed successfully\n");
 
 //
 
 // Otherwise, print the system error.
 
 //
 
 else
 
       fprintf(stderr, "A system error has occurred: %d\n", nStatus);
 
 return 0;
 
 }

PS: While you can still use NetUserChangePassword you should always try to use the LDAP/ADSI method for changing the password as LDAP over SSL is more secured than Net API calls