123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290 |
- // Copyright 2011 The Go Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- package ldap
- import (
- "errors"
- "io/ioutil"
- "os"
- ber "gopkg.in/asn1-ber.v1"
- )
- // LDAP Application Codes
- const (
- ApplicationBindRequest = 0
- ApplicationBindResponse = 1
- ApplicationUnbindRequest = 2
- ApplicationSearchRequest = 3
- ApplicationSearchResultEntry = 4
- ApplicationSearchResultDone = 5
- ApplicationModifyRequest = 6
- ApplicationModifyResponse = 7
- ApplicationAddRequest = 8
- ApplicationAddResponse = 9
- ApplicationDelRequest = 10
- ApplicationDelResponse = 11
- ApplicationModifyDNRequest = 12
- ApplicationModifyDNResponse = 13
- ApplicationCompareRequest = 14
- ApplicationCompareResponse = 15
- ApplicationAbandonRequest = 16
- ApplicationSearchResultReference = 19
- ApplicationExtendedRequest = 23
- ApplicationExtendedResponse = 24
- )
- // ApplicationMap contains human readable descriptions of LDAP Application Codes
- var ApplicationMap = map[uint8]string{
- ApplicationBindRequest: "Bind Request",
- ApplicationBindResponse: "Bind Response",
- ApplicationUnbindRequest: "Unbind Request",
- ApplicationSearchRequest: "Search Request",
- ApplicationSearchResultEntry: "Search Result Entry",
- ApplicationSearchResultDone: "Search Result Done",
- ApplicationModifyRequest: "Modify Request",
- ApplicationModifyResponse: "Modify Response",
- ApplicationAddRequest: "Add Request",
- ApplicationAddResponse: "Add Response",
- ApplicationDelRequest: "Del Request",
- ApplicationDelResponse: "Del Response",
- ApplicationModifyDNRequest: "Modify DN Request",
- ApplicationModifyDNResponse: "Modify DN Response",
- ApplicationCompareRequest: "Compare Request",
- ApplicationCompareResponse: "Compare Response",
- ApplicationAbandonRequest: "Abandon Request",
- ApplicationSearchResultReference: "Search Result Reference",
- ApplicationExtendedRequest: "Extended Request",
- ApplicationExtendedResponse: "Extended Response",
- }
- // Ldap Behera Password Policy Draft 10 (https://tools.ietf.org/html/draft-behera-ldap-password-policy-10)
- const (
- BeheraPasswordExpired = 0
- BeheraAccountLocked = 1
- BeheraChangeAfterReset = 2
- BeheraPasswordModNotAllowed = 3
- BeheraMustSupplyOldPassword = 4
- BeheraInsufficientPasswordQuality = 5
- BeheraPasswordTooShort = 6
- BeheraPasswordTooYoung = 7
- BeheraPasswordInHistory = 8
- )
- // BeheraPasswordPolicyErrorMap contains human readable descriptions of Behera Password Policy error codes
- var BeheraPasswordPolicyErrorMap = map[int8]string{
- BeheraPasswordExpired: "Password expired",
- BeheraAccountLocked: "Account locked",
- BeheraChangeAfterReset: "Password must be changed",
- BeheraPasswordModNotAllowed: "Policy prevents password modification",
- BeheraMustSupplyOldPassword: "Policy requires old password in order to change password",
- BeheraInsufficientPasswordQuality: "Password fails quality checks",
- BeheraPasswordTooShort: "Password is too short for policy",
- BeheraPasswordTooYoung: "Password has been changed too recently",
- BeheraPasswordInHistory: "New password is in list of old passwords",
- }
- // Adds descriptions to an LDAP Response packet for debugging
- func addLDAPDescriptions(packet *ber.Packet) (err error) {
- defer func() {
- if r := recover(); r != nil {
- err = NewError(ErrorDebugging, errors.New("ldap: cannot process packet to add descriptions"))
- }
- }()
- packet.Description = "LDAP Response"
- packet.Children[0].Description = "Message ID"
- application := uint8(packet.Children[1].Tag)
- packet.Children[1].Description = ApplicationMap[application]
- switch application {
- case ApplicationBindRequest:
- addRequestDescriptions(packet)
- case ApplicationBindResponse:
- addDefaultLDAPResponseDescriptions(packet)
- case ApplicationUnbindRequest:
- addRequestDescriptions(packet)
- case ApplicationSearchRequest:
- addRequestDescriptions(packet)
- case ApplicationSearchResultEntry:
- packet.Children[1].Children[0].Description = "Object Name"
- packet.Children[1].Children[1].Description = "Attributes"
- for _, child := range packet.Children[1].Children[1].Children {
- child.Description = "Attribute"
- child.Children[0].Description = "Attribute Name"
- child.Children[1].Description = "Attribute Values"
- for _, grandchild := range child.Children[1].Children {
- grandchild.Description = "Attribute Value"
- }
- }
- if len(packet.Children) == 3 {
- addControlDescriptions(packet.Children[2])
- }
- case ApplicationSearchResultDone:
- addDefaultLDAPResponseDescriptions(packet)
- case ApplicationModifyRequest:
- addRequestDescriptions(packet)
- case ApplicationModifyResponse:
- case ApplicationAddRequest:
- addRequestDescriptions(packet)
- case ApplicationAddResponse:
- case ApplicationDelRequest:
- addRequestDescriptions(packet)
- case ApplicationDelResponse:
- case ApplicationModifyDNRequest:
- addRequestDescriptions(packet)
- case ApplicationModifyDNResponse:
- case ApplicationCompareRequest:
- addRequestDescriptions(packet)
- case ApplicationCompareResponse:
- case ApplicationAbandonRequest:
- addRequestDescriptions(packet)
- case ApplicationSearchResultReference:
- case ApplicationExtendedRequest:
- addRequestDescriptions(packet)
- case ApplicationExtendedResponse:
- }
- return nil
- }
- func addControlDescriptions(packet *ber.Packet) {
- packet.Description = "Controls"
- for _, child := range packet.Children {
- child.Description = "Control"
- child.Children[0].Description = "Control Type (" + ControlTypeMap[child.Children[0].Value.(string)] + ")"
- value := child.Children[1]
- if len(child.Children) == 3 {
- child.Children[1].Description = "Criticality"
- value = child.Children[2]
- }
- value.Description = "Control Value"
- switch child.Children[0].Value.(string) {
- case ControlTypePaging:
- value.Description += " (Paging)"
- if value.Value != nil {
- valueChildren := ber.DecodePacket(value.Data.Bytes())
- value.Data.Truncate(0)
- value.Value = nil
- valueChildren.Children[1].Value = valueChildren.Children[1].Data.Bytes()
- value.AppendChild(valueChildren)
- }
- value.Children[0].Description = "Real Search Control Value"
- value.Children[0].Children[0].Description = "Paging Size"
- value.Children[0].Children[1].Description = "Cookie"
- case ControlTypeBeheraPasswordPolicy:
- value.Description += " (Password Policy - Behera Draft)"
- if value.Value != nil {
- valueChildren := ber.DecodePacket(value.Data.Bytes())
- value.Data.Truncate(0)
- value.Value = nil
- value.AppendChild(valueChildren)
- }
- sequence := value.Children[0]
- for _, child := range sequence.Children {
- if child.Tag == 0 {
- //Warning
- child := child.Children[0]
- packet := ber.DecodePacket(child.Data.Bytes())
- val, ok := packet.Value.(int64)
- if ok {
- if child.Tag == 0 {
- //timeBeforeExpiration
- value.Description += " (TimeBeforeExpiration)"
- child.Value = val
- } else if child.Tag == 1 {
- //graceAuthNsRemaining
- value.Description += " (GraceAuthNsRemaining)"
- child.Value = val
- }
- }
- } else if child.Tag == 1 {
- // Error
- packet := ber.DecodePacket(child.Data.Bytes())
- val, ok := packet.Value.(int8)
- if !ok {
- val = -1
- }
- child.Description = "Error"
- child.Value = val
- }
- }
- }
- }
- }
- func addRequestDescriptions(packet *ber.Packet) {
- packet.Description = "LDAP Request"
- packet.Children[0].Description = "Message ID"
- packet.Children[1].Description = ApplicationMap[uint8(packet.Children[1].Tag)]
- if len(packet.Children) == 3 {
- addControlDescriptions(packet.Children[2])
- }
- }
- func addDefaultLDAPResponseDescriptions(packet *ber.Packet) {
- resultCode, _ := getLDAPResultCode(packet)
- packet.Children[1].Children[0].Description = "Result Code (" + LDAPResultCodeMap[resultCode] + ")"
- packet.Children[1].Children[1].Description = "Matched DN"
- packet.Children[1].Children[2].Description = "Error Message"
- if len(packet.Children[1].Children) > 3 {
- packet.Children[1].Children[3].Description = "Referral"
- }
- if len(packet.Children) == 3 {
- addControlDescriptions(packet.Children[2])
- }
- }
- // DebugBinaryFile reads and prints packets from the given filename
- func DebugBinaryFile(fileName string) error {
- file, err := ioutil.ReadFile(fileName)
- if err != nil {
- return NewError(ErrorDebugging, err)
- }
- ber.PrintBytes(os.Stdout, file, "")
- packet := ber.DecodePacket(file)
- addLDAPDescriptions(packet)
- ber.PrintPacket(packet)
- return nil
- }
- var hex = "0123456789abcdef"
- func mustEscape(c byte) bool {
- return c > 0x7f || c == '(' || c == ')' || c == '\\' || c == '*' || c == 0
- }
- // EscapeFilter escapes from the provided LDAP filter string the special
- // characters in the set `()*\` and those out of the range 0 < c < 0x80,
- // as defined in RFC4515.
- func EscapeFilter(filter string) string {
- escape := 0
- for i := 0; i < len(filter); i++ {
- if mustEscape(filter[i]) {
- escape++
- }
- }
- if escape == 0 {
- return filter
- }
- buf := make([]byte, len(filter)+escape*2)
- for i, j := 0, 0; i < len(filter); i++ {
- c := filter[i]
- if mustEscape(c) {
- buf[j+0] = '\\'
- buf[j+1] = hex[c>>4]
- buf[j+2] = hex[c&0xf]
- j += 3
- } else {
- buf[j] = c
- j++
- }
- }
- return string(buf)
- }
|