forked from Shiloh/githaven
303 lines
11 KiB
Go
303 lines
11 KiB
Go
// 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"
|
|
|
|
"github.com/gogits/gogs/modules/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[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, 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[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 error
|
|
ResultCode uint8
|
|
}
|
|
|
|
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 uint8, err error) error {
|
|
return &Error{ResultCode: resultCode, Err: err}
|
|
}
|
|
|
|
func getLDAPResultCode(packet *ber.Packet) (code uint8, 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 uint8(response.Children[0].Value.(uint64)), response.Children[2].Value.(string)
|
|
}
|
|
}
|
|
|
|
return ErrorNetwork, "Invalid packet format"
|
|
}
|