go-ldap / ldap

Basic LDAP v3 functionality for the GO programming language.
Other
2.25k stars 355 forks source link

panic: Multiple panics in GetLDAPError #453

Closed TomSellers closed 1 year ago

TomSellers commented 1 year ago

GetLDAPError has been observed to panic when calling SimpleBind against certain targets.


panic: interface conversion: interface {} is nil, not string

[github.com/go-ldap/ldap/v3.GetLDAPError(0xc009b6ccb0)](http://github.com/go-ldap/ldap/v3.GetLDAPError(0xc009b6ccb0))
    /home/runner/go/pkg/mod/github.com/go-ldap/ldap/v3@v3.4.5/error.go:216 +0x368
[github.com/go-ldap/ldap/v3.(*Conn).SimpleBind](http://github.com/go-ldap/ldap/v3.(*Conn).SimpleBind)(0xc013ed47e0, 0xc004d16300?)
    /home/runner/go/pkg/mod/github.com/go-ldap/ldap/v3@v3.4.5/bind.go:90 +0x2b4
[github.com/go-ldap/ldap/v3.(*Conn).UnauthenticatedBind(...)](http://github.com/go-ldap/ldap/v3.(*Conn).UnauthenticatedBind(...))
    /home/runner/go/pkg/mod/github.com/go-ldap/ldap/v3@v3.4.5/bind.go:121

While I cannot provide the original packets that triggered this initially I have been able to reproduce this panic and one other using a modified version of the existing TestGetLDAPError test for GetLDAPError.


Reproducer for interface conversion: interface {} is nil, not string at error.go:216

package main

import (
    "fmt"

    ber "github.com/go-asn1-ber/asn1-ber"
    ldap "github.com/go-ldap/ldap/v3"
)

func main() {
    bindResponse := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ldap.ApplicationBindResponse, nil, "Bind Response")
    bindResponse.AppendChild(ber.Encode(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, int64(ldap.LDAPResultInvalidCredentials), "resultCode"))
    bindResponse.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, "dc=example,dc=org", "matchedDN"))

    // Original message included the line below
    // bindResponse.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, diagnosticMessage, "diagnosticMessage"))
    bindResponse.AppendChild(ber.Encode(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, nil, "diagnosticMessage"))

    packet := ber.NewSequence("LDAPMessage")
    packet.AppendChild(ber.Encode(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, int64(0), "messageID"))
    packet.AppendChild(bindResponse)

    fmt.Printf("packet: %+v\n", packet)
    _ = ldap.GetLDAPError(packet)
}

Results

go run main.go
packet: &{Identifier:{ClassType:0 TagType:32 Tag:16} Value:<nil> ByteValue:[] Data:adc=example,dc=org Children:[0x140000ee2a0 0x140000ee070] Description:LDAPMessage}
panic: interface conversion: interface {} is nil, not string

goroutine 1 [running]:
github.com/go-ldap/ldap/v3.GetLDAPError(0x140000ee230)
        /Users/tom.sellers/go/pkg/mod/github.com/go-ldap/ldap/v3@v3.4.5/error.go:216 +0x380
main.main()
        /Users/tom.sellers/Downloads/ldap-testing/main.go:24 +0x19c
exit status 2

Related code

https://github.com/go-ldap/ldap/blob/36463555bb76591f89b1869161b6ef228e947d19/error.go#L213-L217


Reproducer for interface conversion: interface {} is string, not int64 at error.go:209

package main

import (
    ber "github.com/go-asn1-ber/asn1-ber"
    ldap "github.com/go-ldap/ldap/v3"
)

func main() {
    diagnosticMessage := "Detailed error message"
    bindResponse := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ldap.ApplicationBindResponse, nil, "Bind Response")

    bindResponse.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, "dc=example,dc=org", "matchedDN"))
    bindResponse.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, diagnosticMessage, "diagnosticMessage"))

    // The following was originally the first call to bindResponse.AppendChild()
    bindResponse.AppendChild(ber.Encode(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, int64(ldap.LDAPResultInvalidCredentials), "resultCode"))

    packet := ber.NewSequence("LDAPMessage")
    packet.AppendChild(ber.Encode(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, int64(0), "messageID"))
    packet.AppendChild(bindResponse)
    _ = ldap.GetLDAPError(packet)
}

Results

go run main.go
panic: interface conversion: interface {} is string, not int64

goroutine 1 [running]:
github.com/go-ldap/ldap/v3.GetLDAPError(0x1400011c230)
        /Users/tom.sellers/go/pkg/mod/github.com/go-ldap/ldap/v3@v3.4.5/error.go:209 +0x3a0
main.main()
        /Users/tom.sellers/Downloads/ldap-testing/main.go:21 +0x158
exit status 2

Related code

https://github.com/go-ldap/ldap/blob/36463555bb76591f89b1869161b6ef228e947d19/error.go#L208-L209