// 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" "fmt" "io/ioutil" "4a.si/asn1-ber" ) // 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 ) 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 Result Codes const ( LDAPResultSuccess = 0 LDAPResultOperationsError = 1 LDAPResultProtocolError = 2 LDAPResultTimeLimitExceeded = 3 LDAPResultSizeLimitExceeded = 4 LDAPResultCompareFalse = 5 LDAPResultCompareTrue = 6 LDAPResultAuthMethodNotSupported = 7 LDAPResultStrongAuthRequired = 8 LDAPResultReferral = 10 LDAPResultAdminLimitExceeded = 11 LDAPResultUnavailableCriticalExtension = 12 LDAPResultConfidentialityRequired = 13 LDAPResultSaslBindInProgress = 14 LDAPResultNoSuchAttribute = 16 LDAPResultUndefinedAttributeType = 17 LDAPResultInappropriateMatching = 18 LDAPResultConstraintViolation = 19 LDAPResultAttributeOrValueExists = 20 LDAPResultInvalidAttributeSyntax = 21 LDAPResultNoSuchObject = 32 LDAPResultAliasProblem = 33 LDAPResultInvalidDNSyntax = 34 LDAPResultAliasDereferencingProblem = 36 LDAPResultInappropriateAuthentication = 48 LDAPResultInvalidCredentials = 49 LDAPResultInsufficientAccessRights = 50 LDAPResultBusy = 51 LDAPResultUnavailable = 52 LDAPResultUnwillingToPerform = 53 LDAPResultLoopDetect = 54 LDAPResultNamingViolation = 64 LDAPResultObjectClassViolation = 65 LDAPResultNotAllowedOnNonLeaf = 66 LDAPResultNotAllowedOnRDN = 67 LDAPResultEntryAlreadyExists = 68 LDAPResultObjectClassModsProhibited = 69 LDAPResultAffectsMultipleDSAs = 71 LDAPResultOther = 80 ErrorNetwork = 200 ErrorFilterCompile = 201 ErrorFilterDecompile = 202 ErrorDebugging = 203 ) var LDAPResultCodeMap = map[LDAPResultCode]string{ LDAPResultSuccess: "Success", LDAPResultOperationsError: "Operations Error", LDAPResultProtocolError: "Protocol Error", LDAPResultTimeLimitExceeded: "Time Limit Exceeded", LDAPResultSizeLimitExceeded: "Size Limit Exceeded", LDAPResultCompareFalse: "Compare False", LDAPResultCompareTrue: "Compare True", LDAPResultAuthMethodNotSupported: "Auth Method Not Supported", LDAPResultStrongAuthRequired: "Strong Auth Required", LDAPResultReferral: "Referral", LDAPResultAdminLimitExceeded: "Admin Limit Exceeded", LDAPResultUnavailableCriticalExtension: "Unavailable Critical Extension", LDAPResultConfidentialityRequired: "Confidentiality Required", LDAPResultSaslBindInProgress: "Sasl Bind In Progress", LDAPResultNoSuchAttribute: "No Such Attribute", LDAPResultUndefinedAttributeType: "Undefined Attribute Type", LDAPResultInappropriateMatching: "Inappropriate Matching", LDAPResultConstraintViolation: "Constraint Violation", LDAPResultAttributeOrValueExists: "Attribute Or Value Exists", LDAPResultInvalidAttributeSyntax: "Invalid Attribute Syntax", LDAPResultNoSuchObject: "No Such Object", LDAPResultAliasProblem: "Alias Problem", LDAPResultInvalidDNSyntax: "Invalid DN Syntax", LDAPResultAliasDereferencingProblem: "Alias Dereferencing Problem", LDAPResultInappropriateAuthentication: "Inappropriate Authentication", LDAPResultInvalidCredentials: "Invalid Credentials", LDAPResultInsufficientAccessRights: "Insufficient Access Rights", LDAPResultBusy: "Busy", LDAPResultUnavailable: "Unavailable", LDAPResultUnwillingToPerform: "Unwilling To Perform", LDAPResultLoopDetect: "Loop Detect", LDAPResultNamingViolation: "Naming Violation", LDAPResultObjectClassViolation: "Object Class Violation", LDAPResultNotAllowedOnNonLeaf: "Not Allowed On Non Leaf", LDAPResultNotAllowedOnRDN: "Not Allowed On RDN", LDAPResultEntryAlreadyExists: "Entry Already Exists", LDAPResultObjectClassModsProhibited: "Object Class Mods Prohibited", LDAPResultAffectsMultipleDSAs: "Affects Multiple DSAs", LDAPResultOther: "Other", } // Other LDAP constants const ( LDAPBindAuthSimple = 0 LDAPBindAuthSASL = 3 ) type LDAPResultCode uint8 type Attribute struct { attrType string attrVals []string } type AddRequest struct { dn string attributes []Attribute } type DeleteRequest struct { dn string } type ModifyDNRequest struct { dn string newrdn string deleteoldrdn bool newSuperior string } type AttributeValueAssertion struct { attributeDesc string assertionValue string } type CompareRequest struct { dn string ava []AttributeValueAssertion } type ExtendedRequest struct { requestName string requestValue string } // 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 := 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" } } } func addRequestDescriptions(packet *ber.Packet) { packet.Description = "LDAP Request" packet.Children[0].Description = "Message ID" packet.Children[1].Description = ApplicationMap[packet.Children[1].Tag] if len(packet.Children) == 3 { addControlDescriptions(packet.Children[2]) } } func addDefaultLDAPResponseDescriptions(packet *ber.Packet) { resultCode := packet.Children[1].Children[0].Value.(uint64) packet.Children[1].Children[0].Description = "Result Code (" + LDAPResultCodeMap[LDAPResultCode(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]) } } func DebugBinaryFile(fileName string) error { file, err := ioutil.ReadFile(fileName) if err != nil { return NewError(ErrorDebugging, err) } ber.PrintBytes(file, "") packet := ber.DecodePacket(file) addLDAPDescriptions(packet) ber.PrintPacket(packet) return nil } type Error struct { Err error ResultCode LDAPResultCode } func (e *Error) Error() string { return fmt.Sprintf("LDAP Result Code %d %q: %s", e.ResultCode, LDAPResultCodeMap[e.ResultCode], e.Err.Error()) } func NewError(resultCode LDAPResultCode, err error) error { return &Error{ResultCode: resultCode, Err: err} } func getLDAPResultCode(packet *ber.Packet) (code LDAPResultCode, description string) { if len(packet.Children) >= 2 { response := packet.Children[1] if response.ClassType == ber.ClassApplication && response.TagType == ber.TypeConstructed && len(response.Children) == 3 { return LDAPResultCode(response.Children[0].Value.(uint64)), response.Children[2].Value.(string) } } return ErrorNetwork, "Invalid packet format" }