Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/windows/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Windows 如何以编程方式检查;密码必须满足复杂性要求”;组策略设置?_Windows_Security_Winapi_Group Policy - Fatal编程技术网

Windows 如何以编程方式检查;密码必须满足复杂性要求”;组策略设置?

Windows 如何以编程方式检查;密码必须满足复杂性要求”;组策略设置?,windows,security,winapi,group-policy,Windows,Security,Winapi,Group Policy,窗口有五个与密码安全性相关的组策略设置: 强制执行密码历史记录 最长密码期限 最低密码期限 最小密码长度 密码必须满足复杂性要求 使用可逆加密存储密码 我知道如何使用阅读。但它不支持检查是否启用了密码复杂性要求: 强制执行密码历史记录:usrmod0\u密码历史记录 最大密码期限:usrmod0\u max\u passwd\u期限 最小密码期限:usrmod0\u min\u passwd\u期限 最小密码长度:usrmod0\u min\u passwd\u len 密码必须满足复杂

窗口有五个与密码安全性相关的组策略设置:

  • 强制执行密码历史记录
  • 最长密码期限
  • 最低密码期限
  • 最小密码长度
  • 密码必须满足复杂性要求
  • 使用可逆加密存储密码

我知道如何使用阅读。但它不支持检查是否启用了密码复杂性要求:

  • 强制执行密码历史记录
    usrmod0\u密码历史记录
  • 最大密码期限
    usrmod0\u max\u passwd\u期限
  • 最小密码期限
    usrmod0\u min\u passwd\u期限
  • 最小密码长度
    usrmod0\u min\u passwd\u len
  • 密码必须满足复杂性要求
  • 使用可逆加密存储密码:
我还知道WMI的RSOP(“策略的结果集”)不合适。我当然不会(也就是说,我想要支持的方式)

注意:我不关心“使用可逆加密存储密码”组策略设置

奖金 您还可以使用
NetUserModalsGet
API检索帐户锁定策略设置:

  • 帐户锁定持续时间
    usrmod3\u锁定持续时间
  • 帐户锁定阈值
    usrmod3\u锁定阈值
  • 之后重置帐户锁定计数器:
    usrmod3\u锁定\u观察\u窗口
因此,将所有与密码相关的组策略选项四舍五入;“必须满足复杂性要求”除外


为完整起见,假设一台未加入域的机器(即没有要查询的AD服务器、没有要查询的RSOP等)。

这可以使用SAM()API访问

这个API(由SAMLIB.DLL提供)没有直接文档化(没有头,没有SDK),但是使用它的“协议”在这里被文档化了:,您“只”需要删除所描述的
SamrXXXX
方法中的
r

这里讨论的是(以及相关的SamSetInformationDomain),它将为您提供一个结构

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,
该成员可以包含
域\u密码\u复合体
标志:

DOMAIN_PASSWORD_COMPLEX
0x00000001
The server enforces password complexity policy. See section 3.1.1.7.2 for details of the password policy. 
我提供了一些C#样品来检查这一点

第一个转储当前计算机的SAM服务器所服务的所有域的策略:

        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);
            }
        }
第二个读取并更新当前计算机域的策略:

        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);
        }
这是
SamServer
实用程序:

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));
        }
        finally
        {
            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));
        }
        finally
        {
            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 us = (UNICODE_STRING)Marshal.PtrToStructure(info + IntPtr.Size, typeof(UNICODE_STRING));
            SamFreeMemory(info);
            yield return us.ToString();
            us.Buffer = IntPtr.Zero; // we don't own this one
        }
    }

    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
        {
            get
            {
                return -new TimeSpan(_maxPasswordAge);
            }
            set
            {
                _maxPasswordAge = value.Ticks;
            }
        }

        public TimeSpan MinPasswordAge
        {
            get
            {
                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);
}
公共密封类SamServer:IDisposable
{
私有IntPtr_句柄;
公共SamServer(字符串名称、服务器\u访问\u掩码访问)
{
名称=名称;
检查(SamConnect(新的UNICODE_字符串(名称)、out_句柄、access、IntPtr.Zero));
}
公共字符串名称{get;}
公共空间处置()
{
if(_handle!=IntPtr.Zero)
{
SamCloseHandle(_handle);
_handle=IntPtr.Zero;
}
}
public void SetDomainPasswordInformation(安全标识符domainSid、域\密码\信息passwordInformation)
{
if(domainSid==null)
抛出新ArgumentNullException(nameof(domainSid));
var sid=新字节[domainSid.BinaryLength];
域sid.GetBinaryForm(sid,0);
检查(SamOpenDomain(_handle,DOMAIN,ACCESS,MASK.DOMAIN,WRITE,PASSWORD,PARAMS,sid,out IntPtr DOMAIN));
IntPtr info=Marshal.AllocHGlobal(Marshal.SizeOf(passwordInformation));
Marshal.StructureToPtr(密码信息,信息,false);
尝试
{
检查(SamSetInformationDomain(domain,domain_INFORMATION_CLASS.domain密码信息,info));
}
最后
{
弗里赫全球元帅(信息);
SamCloseHandle(域);
}
}
公共域\密码\信息GetDomainPasswordInformation(安全标识符domainSid)
{
if(domainSid==null)
抛出新ArgumentNullException(nameof(domainSid));
var sid=新字节[domainSid.BinaryLength];
域sid.GetBinaryForm(sid,0);
检查(SamOpenDomain(_handle,DOMAIN,ACCESS,MASK.DOMAIN,READ,PASSWORD,sid,out IntPtr DOMAIN));
var info=IntPtr.Zero;
尝试
{
检查(SamQueryInformationDomain(域、域信息、类、域密码信息、输出信息));
return(DOMAIN_PASSWORD_INFORMATION)Marshal.ptr结构(info,typeof(DOMAIN_PASSWORD_INFORMATION));
}
最后
{
samfreemory(info);
SamCloseHandle(域);
}
}
公共安全标识符GetDomainSid(字符串域)
{
如果(域==null)
抛出新ArgumentNullException(nameof(domain));
检查(SamLookupDomainInSamServer(_句柄,新的UNICODE_字符串(域),out IntPtr sid));
返回新的SecurityIdentifier(sid);
}
公共IEnumerable枚举域()
{
int=0;
while(true)
{
var status=SamEnumerateDomainsInSamServer(_handle,ref cookie,out IntPtr info,1,out int count);
if(status!=NTSTATUS.status\u SUCCESS&&status!=NTSTATUS.status\u MORE\u条目)
检查(状态);
如果(计数=0)
打破
var us=(UNICODE_字符串)Marshal.ptr结构(info+IntPtr.Size,typeof(UNICODE_字符串));
samfreemory(info);
收益率返回us.ToString();
us.Buffer=IntPtr.Zero;//我们没有这个
}
}
私有枚举域信息类
{
DomainPasswordInformation=1,
}
[旗帜]
公共枚举密码\u属性
{
域\u密码\u复合体=0x00000001,
域\u密码\u否\u其他_