windows - How to programatically check the "Password must meet complexity requirements" group policy setting? -


window has 5 group policy settings related password security:

  • enforce password history
  • maximum password age
  • minimum password age
  • minimum password length
  • password must meet complexity requirements
  • store passwords using reversible encryption

enter image description here

i know how use netusermodalsget read most of these items. doesn't support checking if password complexity requirement enabled:

  • enforce password history: usrmod0_password_hist_len
  • maximum password age: usrmod0_max_passwd_age
  • minimum password age: usrmod0_min_passwd_age
  • minimum password length: usrmod0_min_passwd_len
  • password must meet complexity requirements: ?
  • store passwords using reversible encryption:

i know wmi's rsop ("resultant set of policy") unsuitable, as works on domain. , i'm not going crawling through undocumented binary blob (i.e. want supported way).

note: don't care "store passwords using reversible encryption" group policy setting.

bonus

you can use netusermodalsget api retrieve account lockout policy settings:

  • account lockout duration: usrmod3_lockout_duration
  • account lockout threshold: usrmod3_lockout_threshold
  • reset account lockout counter after: usrmod3_lockout_observation_window

thus rounding out password related group policy options; except "must meet complexity requirements".

for completeness, assume non-domain joined machine (i.e. no ad server query, no rsop query, etc).

this accessible using sam (security account manager) apis.

this api (served samlib.dll) not directly documented (no header, no sdk), "protocol" use documented here: [ms-samr]: security account manager (sam) remote protocol (client-to-server), "just" have remove r in described samrxxxx methods.

the ones in question here samqueryinformationdomain (and associated samsetinformationdomain) domain_password_information structure

typedef struct _domain_password_information {    unsigned short minpasswordlength;    unsigned short passwordhistorylength;    unsigned long passwordproperties;    old_large_integer maxpasswordage;    old_large_integer minpasswordage;  } domain_password_information, 

the passwordproperties member can contain domain_password_complex flag:

domain_password_complex 0x00000001 server enforces password complexity policy. see section 3.1.1.7.2 details of password policy.  

i've provided c# samples check this.

first 1 dumps policy domains served current machine's sam server:

        using (samserver server = new samserver(null, samserver.server_access_mask.sam_server_enumerate_domains | samserver.server_access_mask.sam_server_lookup_domain))         {             foreach (string domain in server.enumeratedomains())             {                 console.writeline("domain: " + domain);                  var sid = server.getdomainsid(domain);                 console.writeline(" sid: " + sid);                  var pi = server.getdomainpasswordinformation(sid);                 console.writeline(" maxpasswordage: " + pi.maxpasswordage);                 console.writeline(" minpasswordage: " + pi.minpasswordage);                 console.writeline(" minpasswordlength: " + pi.minpasswordlength);                 console.writeline(" passwordhistorylength: " + pi.passwordhistorylength);                 console.writeline(" passwordproperties: " + pi.passwordproperties);             }         } 

second 1 reads , updates policy current machine's domain:

        using (samserver server = new samserver(null, samserver.server_access_mask.sam_server_all_access))         {             var sid = server.getdomainsid(environment.machinename);             var pi = server.getdomainpasswordinformation(sid);              // remove password complexity             pi.passwordproperties &= ~samserver.password_properties.domain_password_complex;             server.setdomainpasswordinformation(sid, pi);         } 

this samserver utility:

public sealed class samserver : idisposable {     private intptr _handle;      public samserver(string name, server_access_mask access)     {         name = name;         check(samconnect(new unicode_string(name), out _handle, access, intptr.zero));     }      public string name { get; }      public void dispose()     {         if (_handle != intptr.zero)         {             samclosehandle(_handle);             _handle = intptr.zero;         }     }      public void setdomainpasswordinformation(securityidentifier domainsid, domain_password_information passwordinformation)     {         if (domainsid == null)             throw new argumentnullexception(nameof(domainsid));          var sid = new byte[domainsid.binarylength];         domainsid.getbinaryform(sid, 0);          check(samopendomain(_handle, domain_access_mask.domain_write_password_params, sid, out intptr domain));         intptr info = marshal.allochglobal(marshal.sizeof(passwordinformation));         marshal.structuretoptr(passwordinformation, info, false);         try         {             check(samsetinformationdomain(domain, domain_information_class.domainpasswordinformation, info));         }                 {             marshal.freehglobal(info);             samclosehandle(domain);         }     }      public domain_password_information getdomainpasswordinformation(securityidentifier domainsid)     {         if (domainsid == null)             throw new argumentnullexception(nameof(domainsid));          var sid = new byte[domainsid.binarylength];         domainsid.getbinaryform(sid, 0);          check(samopendomain(_handle, domain_access_mask.domain_read_password_parameters, sid, out intptr domain));         var info = intptr.zero;         try         {             check(samqueryinformationdomain(domain, domain_information_class.domainpasswordinformation, out info));             return (domain_password_information)marshal.ptrtostructure(info, typeof(domain_password_information));         }                 {             samfreememory(info);             samclosehandle(domain);         }     }      public securityidentifier getdomainsid(string domain)     {         if (domain == null)             throw new argumentnullexception(nameof(domain));          check(samlookupdomaininsamserver(_handle, new unicode_string(domain), out intptr sid));         return new securityidentifier(sid);     }      public ienumerable<string> enumeratedomains()     {         int cookie = 0;         while (true)         {             var status = samenumeratedomainsinsamserver(_handle, ref cookie, out intptr info, 1, out int count);             if (status != ntstatus.status_success && status != ntstatus.status_more_entries)                 check(status);              if (count == 0)                 break;              var = (unicode_string)marshal.ptrtostructure(info + intptr.size, typeof(unicode_string));             samfreememory(info);             yield return us.tostring();             us.buffer = intptr.zero; // don't own 1         }     }      private enum domain_information_class     {         domainpasswordinformation = 1,     }      [flags]     public enum password_properties     {         domain_password_complex = 0x00000001,         domain_password_no_anon_change = 0x00000002,         domain_password_no_clear_change = 0x00000004,         domain_lockout_admins = 0x00000008,         domain_password_store_cleartext = 0x00000010,         domain_refuse_password_change = 0x00000020,     }      [flags]     private enum domain_access_mask     {         domain_read_password_parameters = 0x00000001,         domain_write_password_params = 0x00000002,         domain_read_other_parameters = 0x00000004,         domain_write_other_parameters = 0x00000008,         domain_create_user = 0x00000010,         domain_create_group = 0x00000020,         domain_create_alias = 0x00000040,         domain_get_alias_membership = 0x00000080,         domain_list_accounts = 0x00000100,         domain_lookup = 0x00000200,         domain_administer_server = 0x00000400,         domain_all_access = 0x000f07ff,         domain_read = 0x00020084,         domain_write = 0x0002047a,         domain_execute = 0x00020301     }      [flags]     public enum server_access_mask     {         sam_server_connect = 0x00000001,         sam_server_shutdown = 0x00000002,         sam_server_initialize = 0x00000004,         sam_server_create_domain = 0x00000008,         sam_server_enumerate_domains = 0x00000010,         sam_server_lookup_domain = 0x00000020,         sam_server_all_access = 0x000f003f,         sam_server_read = 0x00020010,         sam_server_write = 0x0002000e,         sam_server_execute = 0x00020021     }      [structlayout(layoutkind.sequential)]     public struct domain_password_information     {         public short minpasswordlength;         public short passwordhistorylength;         public password_properties passwordproperties;         private long _maxpasswordage;         private long _minpasswordage;          public timespan maxpasswordage         {                         {                 return -new timespan(_maxpasswordage);             }             set             {                 _maxpasswordage = value.ticks;             }         }          public timespan minpasswordage         {                         {                 return -new timespan(_minpasswordage);             }             set             {                 _minpasswordage = value.ticks;             }         }     }      [structlayout(layoutkind.sequential)]     private class unicode_string : idisposable     {         public ushort length;         public ushort maximumlength;         public intptr buffer;          public unicode_string()             : this(null)         {         }          public unicode_string(string s)         {             if (s != null)             {                 length = (ushort)(s.length * 2);                 maximumlength = (ushort)(length + 2);                 buffer = marshal.stringtohglobaluni(s);             }         }          public override string tostring() => buffer != intptr.zero ? marshal.ptrtostringuni(buffer) : null;          protected virtual void dispose(bool disposing)         {             if (buffer != intptr.zero)             {                 marshal.freehglobal(buffer);                 buffer = intptr.zero;             }         }          ~unicode_string() => dispose(false);          public void dispose()         {             dispose(true);             gc.suppressfinalize(this);         }     }      private static void check(ntstatus err)     {         if (err == ntstatus.status_success)             return;          throw new win32exception("error " + err + " (0x" + ((int)err).tostring("x8") + ")");     }      private enum ntstatus     {         status_success = 0x0,         status_more_entries = 0x105,         status_invalid_handle = unchecked((int)0xc0000008),         status_invalid_parameter = unchecked((int)0xc000000d),         status_access_denied = unchecked((int)0xc0000022),         status_object_type_mismatch = unchecked((int)0xc0000024),         status_no_such_domain = unchecked((int)0xc00000df),     }      [dllimport("samlib.dll", charset = charset.unicode)]     private static extern ntstatus samconnect(unicode_string servername, out intptr serverhandle, server_access_mask desiredaccess, intptr objectattributes);      [dllimport("samlib.dll", charset = charset.unicode)]     private static extern ntstatus samclosehandle(intptr serverhandle);      [dllimport("samlib.dll", charset = charset.unicode)]     private static extern ntstatus samfreememory(intptr handle);      [dllimport("samlib.dll", charset = charset.unicode)]     private static extern ntstatus samopendomain(intptr serverhandle, domain_access_mask desiredaccess, byte[] domainid, out intptr domainhandle);      [dllimport("samlib.dll", charset = charset.unicode)]     private static extern ntstatus samlookupdomaininsamserver(intptr serverhandle, unicode_string name, out intptr domainid);      [dllimport("samlib.dll", charset = charset.unicode)]     private static extern ntstatus samqueryinformationdomain(intptr domainhandle, domain_information_class domaininformationclass, out intptr buffer);      [dllimport("samlib.dll", charset = charset.unicode)]     private static extern ntstatus samsetinformationdomain(intptr domainhandle, domain_information_class domaininformationclass, intptr buffer);      [dllimport("samlib.dll", charset = charset.unicode)]     private static extern ntstatus samenumeratedomainsinsamserver(intptr serverhandle, ref int enumerationcontext, out intptr enumerationbuffer, int preferedmaximumlength, out int countreturned); } 

Comments

Popular posts from this blog

c# - Better 64-bit byte array hash -

webrtc - Which ICE candidate am I using and why? -

php - Zend Framework / Skeleton-Application / Composer install issue -