diff options
Diffstat (limited to 'ldap.go')
-rw-r--r-- | ldap.go | 291 |
1 files changed, 291 insertions, 0 deletions
@@ -0,0 +1,291 @@ +// 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. + +// This package provides LDAP client functions. +package ldap + +import ( + "github.com/mmitton/asn1-ber" + "fmt" + "io/ioutil" + "os" +) + +// 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[uint8] 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", +} + +// 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, os.NewError( "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 { + value_children := ber.DecodePacket( value.Data.Bytes() ) + value.Data.Truncate( 0 ) + value.Value = nil + value_children.Children[ 1 ].Value = value_children.Children[ 1 ].Data.Bytes() + value.AppendChild( value_children ) + } + 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[ uint8(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 os.Error + ResultCode uint8 +} + +func (e *Error) String() string { + return fmt.Sprintf( "LDAP Result Code %d %q: %s", e.ResultCode, LDAPResultCodeMap[ e.ResultCode ], e.Err.String() ) +} + +func NewError( ResultCode uint8, Err os.Error ) (* Error) { + return &Error{ ResultCode: ResultCode, Err: Err } +} |