| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289 | // 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 ldapimport (	"errors"	"io/ioutil"	"os"	ber "gopkg.in/asn1-ber.v1")// LDAP Application Codesconst (	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 Codesvar 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 codesvar 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 debuggingfunc 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 filenamefunc 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)}
 |