当我们需要通过代码去查询对象的ACL信息时需要通过LDAP去获取对象的nTSecurityDescriptor属性。
默认通过LDAP查询对象的nTSecurityDescriptor 属性的话通常返回空内容,很多人认为这需要管理员权限才能查到,其实是可以通过普通用户权限获得。
nTSecurityDescriptor属性存储着DACL和SACL还有其他信息,当我们查询该属性时默认检索安全描述符的所有内容,然而当前查询用户可能没有访问全部安全描述符的信息权限,尤其是SACL系统ACL。所以当我们的权限不足以查询这些信息时,AD就会返回空内容。解决这个问题其实很简单,我们只需要告诉AD只查询DACL就行。
要想指定获取DACL就要通过LDAP控件来指定不需要SACL,这个控件就是LDAP_SERVER_SD_FLAGS_OID。
LDAP_SERVER_SD_FLAGS_OID控件与LDAP搜索请求一起使用,以控制要检索的Windows安全描述符部分。DC只返回安全描述符的指定部分。它还与LDAP Modify requests2一起使用,以控制要修改的Windows安全描述符部分。DC仅修改安全描述符的指定部分。
当将该控制发送到DC时,controlValue字段被设置为以下ASN.1结构的BER编码。
代码如下:省略ldap连接部分,构造controls
import(
ber "github.com/go-asn1-ber/asn1-ber"
)
type ControlInteger struct {
ControlType string
Criticality bool
ControlValue int64
}
func main(){
....
var controls []ldap.Control
sdcontrol := &ControlInteger{
ControlType: "1.2.840.113556.1.4.801",
Criticality: true,
ControlValue: int64(7),
}
controls = append(controls, sdcontrol)
fmt.Println(sdcontrol)
searchRequest := ldap.NewSearchRequest(
"dc=test,dc=com",
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
filter,
[]string{"dn", "cn", "nTSecurityDescriptor"},
controls,
)
sr, err := client.Search(searchRequest)
}
// GetControlType rturns the OID
func (c *ControlInteger) GetControlType() string {
return c.ControlType
}
// Encode returns the ber packet representation
func (c *ControlInteger) Encode() *ber.Packet {
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Control")
packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, c.ControlType, "Control Type ("+c.ControlType+")"))
if c.Criticality {
packet.AppendChild(ber.NewBoolean(ber.ClassUniversal, ber.TypePrimitive, ber.TagBoolean, c.Criticality, "Criticality"))
}
// p2 ber.Encode(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, nil, "Control Value")
p2 := ber.Encode(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, nil, "Control Value")
value := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Control Value Sequence")
value.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, c.ControlValue, "Integer"))
p2.AppendChild(value)
packet.AppendChild(p2)
return packet
}
// String returns a human-readable description
func (c *ControlInteger) String() string {
return fmt.Sprintf("Control Type: %v Critiality: %t Control Value: %v", c.ControlType, c.Criticality, c.ControlValue)
}