summaryrefslogblamecommitdiffstats
path: root/ldap.go
blob: 22605e3f5f0563c4a70cb311ab8adeb6f5838482 (plain) (tree)


































































































































































































































































































                                                                                                                      
// 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 }
}