如何通过ldapsearch及Go语言查询Windows AD的MinPwdLen等属性
查询Windows AD密码策略属性(MinPwdLen、MinPwdAge等)
一、关键概念澄清
你在JXplorer中看到的CN=Min-Pwd-Length,CN=Schema,CN=Configuration,DC=XXXX是AD Schema中该属性的定义元数据(比如属性语法、规则),不是实际生效的域密码策略值。实际密码策略值存储在域对象或精细密码策略容器中,这也是ldapdomaindump获取该属性的核心逻辑。
二、ldapsearch命令行查询示例
1. 查询默认域密码策略
默认域密码策略直接存储在域根对象中,执行以下命令:
ldapsearch -x -H ldap://<AD服务器地址>:389 -D "<绑定用户DN>" -W -b "<域根DN>" -s base "(objectClass=domain)" pwdMinLength minPwdAge pwdMaxAge
参数说明:
-x:使用简单绑定认证-H:指定AD服务器的LDAP地址-D:有权限查询AD的用户DN(比如CN=admin,CN=Users,DC=corp,DC=com)-W:交互式输入用户密码-b:查询的基准DN(即你的域根,比如DC=corp,DC=com)-s base:仅查询基准DN本身(不递归子节点)(objectClass=domain):过滤条件,匹配域根对象- 末尾属性映射:
pwdMinLength对应MinPwdLen,minPwdAge对应MinPwdAge,pwdMaxAge对应密码最长有效期
2. 查询精细密码策略(Fine-Grained Password Policies)
如果AD使用了精细密码策略,查询基准DN为密码策略容器:
ldapsearch -x -H ldap://<AD服务器地址>:389 -D "<绑定用户DN>" -W -b "CN=Password Settings Container,CN=System,<域根DN>" -s sub "(objectClass=msDS-PasswordSettings)" msDS-MinimumPasswordLength msDS-MinimumPasswordAge
属性映射:
msDS-MinimumPasswordLength→ MinPwdLenmsDS-MinimumPasswordAge→ MinPwdAge
三、Go语言查询示例(基于go-ldap库)
以下实现基于github.com/go-ldap/ldap/v3库,底层封装了ldap_search_ext_s逻辑:
package main import ( "fmt" "log" "github.com/go-ldap/ldap/v3" ) func main() { // AD连接配置 ldapAddr := "<AD服务器地址>:389" bindDN := "<绑定用户DN>" bindPwd := "<用户密码>" domainBaseDN := "<域根DN>" // 建立LDAP连接 l, err := ldap.DialURL(fmt.Sprintf("ldap://%s", ldapAddr)) if err != nil { log.Fatalf("LDAP连接失败: %v", err) } defer l.Close() // 用户绑定认证 if err := l.Bind(bindDN, bindPwd); err != nil { log.Fatalf("用户绑定失败: %v", err) } // 构建查询请求 searchReq := ldap.NewSearchRequest( domainBaseDN, ldap.ScopeBaseObject, // 仅查询基准DN本身 ldap.NeverDerefAliases, 0, 0, false, "(objectClass=domain)", []string{"pwdMinLength", "minPwdAge", "pwdMaxAge"}, // 目标属性 nil, ) // 执行查询 sr, err := l.Search(searchReq) if err != nil { log.Fatalf("LDAP查询失败: %v", err) } // 处理结果 if len(sr.Entries) == 0 { log.Fatal("未找到域根对象") } entry := sr.Entries[0] fmt.Printf("域DN: %s\n", entry.DN) fmt.Printf("最小密码长度(MinPwdLen): %s\n", entry.GetAttributeValue("pwdMinLength")) // 解析minPwdAge(AD中存储为100纳秒间隔字符串) if minPwdAgeStr := entry.GetAttributeValue("minPwdAge"); minPwdAgeStr != "" { minPwdAge, err := ldap.ParseInterval(minPwdAgeStr) if err != nil { log.Printf("解析minPwdAge失败: %v", err) } else { fmt.Printf("最小密码年龄(MinPwdAge): %s\n", minPwdAge.String()) fmt.Printf("最小密码年龄(天数): %.1f\n", minPwdAge.Hours()/24) } } }
四、Cgo直接调用ldap_search_ext_s示例
如果你的Go应用直接通过Cgo调用系统LDAP库的ldap_search_ext_s函数,参考以下片段:
package main /* #include <ldap.h> */ import "C" import ( "fmt" "log" "unsafe" ) func main() { // 初始化LDAP连接 ld := C.ldap_init(C.CString("<AD服务器地址>"), C.LDAP_PORT) if ld == nil { log.Fatal("LDAP初始化失败") } defer C.ldap_unbind_ext_s(ld, nil, nil) // 设置LDAPv3协议 version := C.int(C.LDAP_VERSION3) C.ldap_set_option(ld, C.LDAP_OPT_PROTOCOL_VERSION, unsafe.Pointer(&version)) // 用户绑定 bindDN := C.CString("<绑定用户DN>") bindPwd := C.CString("<用户密码>") if err := C.ldap_simple_bind_s(ld, bindDN, bindPwd); err != C.LDAP_SUCCESS { log.Fatalf("绑定失败,错误码: %d", err) } C.free(unsafe.Pointer(bindDN)) C.free(unsafe.Pointer(bindPwd)) // 构建查询参数 baseDN := C.CString("<域根DN>") filter := C.CString("(objectClass=domain)") attrs := []*C.char{C.CString("pwdMinLength"), C.CString("minPwdAge"), nil} var res *C.LDAPMessage // 调用ldap_search_ext_s执行查询 if err := C.ldap_search_ext_s( ld, baseDN, C.LDAP_SCOPE_BASE, filter, &attrs[0], 0, nil, nil, nil, 0, &res, ); err != C.LDAP_SUCCESS { log.Fatalf("查询失败,错误码: %d", err) } defer C.ldap_msgfree(res) // 释放资源 C.free(unsafe.Pointer(baseDN)) C.free(unsafe.Pointer(filter)) for _, attr := range attrs { if attr != nil { C.free(unsafe.Pointer(attr)) } } // 遍历结果 entry := C.ldap_first_entry(ld, res) for entry != nil { // 获取pwdMinLength val := C.ldap_get_values(ld, entry, C.CString("pwdMinLength")) if val != nil { fmt.Printf("最小密码长度: %s\n", C.GoString(val[0])) C.ldap_value_free(val) } // 获取minPwdAge val = C.ldap_get_values(ld, entry, C.CString("minPwdAge")) if val != nil { fmt.Printf("最小密码年龄(原始值): %s\n", C.GoString(val[0])) C.ldap_value_free(val) } entry = C.ldap_next_entry(ld, entry) } }
内容的提问来源于stack exchange,提问作者DC007
相关产品推荐
相关产品推荐

