Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions v3/bind.go
Original file line number Diff line number Diff line change
Expand Up @@ -293,11 +293,10 @@ func (l *Conn) DigestMD5Bind(digestMD5BindRequest *DigestMD5BindRequest) (*Diges
return result, GetLDAPError(packet)
}
if ber.Type(resultCodeChild.Tag) == ber.Type(ber.TagInteger) || ber.Type(resultCodeChild.Tag) == ber.Type(ber.TagEnumerated) {
code, rerr := packetInt64(resultCodeChild)
resultCode, rerr := packetResultCode(resultCodeChild)
if rerr != nil {
return result, GetLDAPError(packet)
}
resultCode := uint16(code)
if resultCode == 14 {
msgCtx, err := l.doRequest(digestMD5BindRequest)
if err != nil {
Expand Down
6 changes: 2 additions & 4 deletions v3/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,11 +218,10 @@ func parseLDAPResult(packet *ber.Packet) (resultCode uint16, matchedDN, diagnost
return 0, "", "", err
}

v, err := packetInt64(children[0])
resultCode, err = packetResultCode(children[0])
if err != nil {
return
}
resultCode = uint16(v)

if matchedDN, err = packetString(children[1]); err != nil {
return
Expand Down Expand Up @@ -251,12 +250,11 @@ func GetLDAPError(packet *ber.Packet) error {
return &Error{ResultCode: ErrorNetwork, Err: fmt.Errorf("invalid result code in packet"), Packet: packet}
}
if ber.Type(resultCodeChild.Tag) == ber.Type(ber.TagInteger) || ber.Type(resultCodeChild.Tag) == ber.Type(ber.TagEnumerated) {
code, err := packetInt64(resultCodeChild)
resultCode, err := packetResultCode(resultCodeChild)
if err != nil {
return &Error{ResultCode: ErrorNetwork, Err: fmt.Errorf("invalid result code in packet"), Packet: packet}
}

resultCode := uint16(code)
if resultCode == 0 { // No error
return nil
}
Expand Down
32 changes: 32 additions & 0 deletions v3/error_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,24 @@ func generateGetLDAPErrorCorpus() map[string]testCorpusErrorEntry {
expectedMessage: "",
}

// A resultCode outside the uint16 range the package exposes must be
// rejected. Narrowing it maps any multiple of 2^16 onto success(0), so a
// reply carrying no success code would be reported to the caller as a
// successful operation.
bindResponse = ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationBindResponse, nil, "Bind Response")
bindResponse.AppendChild(ber.Encode(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, int64(65536), "resultCode"))
bindResponse.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, "", "matchedDN"))
bindResponse.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, "", "diagnosticMessage"))
packet = ber.NewSequence("LDAPMessage")
packet.AppendChild(ber.Encode(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, int64(0), "messageID"))
packet.AppendChild(bindResponse)
corpus["result code out of range"] = testCorpusErrorEntry{
packet: packet,
expectedResultCode: ErrorNetwork,
expectedMessage: "invalid result code in packet",
shouldError: true,
}

// Test that responses with an unexpected ordering or combination of children
// don't cause a panic.
bindResponse = ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationBindResponse, nil, "Bind Response")
Expand Down Expand Up @@ -420,6 +438,20 @@ func TestParseLDAPResult(t *testing.T) {
}(),
wantErr: true,
},
{
name: "resultCode out of range",
packet: func() *ber.Packet {
resp := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationSearchResultDone, nil, "SearchResultDone")
resp.AppendChild(ber.Encode(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, int64(65536), "resultCode"))
resp.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, "", "matchedDN"))
resp.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, "", "diagnosticMessage"))
pkt := ber.NewSequence("LDAPMessage")
pkt.AppendChild(ber.Encode(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, int64(1), "messageID"))
pkt.AppendChild(resp)
return pkt
}(),
wantErr: true,
},
{
name: "matchedDN wrong type",
packet: func() *ber.Packet {
Expand Down
17 changes: 17 additions & 0 deletions v3/packet.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package ldap
import (
"errors"
"fmt"
"math"

ber "github.com/go-asn1-ber/asn1-ber"
)
Expand Down Expand Up @@ -107,6 +108,22 @@ func packetInt64(p *ber.Packet) (int64, error) {
return i, nil
}

// packetResultCode returns the LDAPResult resultCode held by p. RFC 4511
// declares resultCode an ENUMERATED and the codes it assigns all fit the uint16
// this package exposes, so a value outside that range is malformed rather than
// merely unknown. Narrowing it instead would alias it onto an unrelated code,
// and any multiple of 2^16 onto success(0).
func packetResultCode(p *ber.Packet) (uint16, error) {
code, err := packetInt64(p)
if err != nil {
return 0, err
}
if code < 0 || code > math.MaxUint16 {
return 0, malformedf("result code %d out of range", code)
}
return uint16(code), nil
}

// packetBool returns the bool value of p, whose schema position or BOOLEAN tag
// fixed it as a boolean.
func packetBool(p *ber.Packet) (bool, error) {
Expand Down
12 changes: 12 additions & 0 deletions v3/packet_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,18 @@ func TestPacketLeafConversions(t *testing.T) {
if b, err := packetBool(newTestBool(true)); err != nil || !b {
t.Fatalf("packetBool: got %v, %v", b, err)
}
if c, err := packetResultCode(newTestInt(49)); err != nil || c != 49 {
t.Fatalf("packetResultCode: got %d, %v", c, err)
}

// A resultCode outside the uint16 range is malformed, not merely unknown:
// narrowing it aliases it onto an unrelated code, and any multiple of 2^16
// onto success(0).
for _, code := range []int64{-1, -65536, 65536, 131072} {
if _, err := packetResultCode(newTestInt(code)); !errors.Is(err, ErrMalformedPacket) {
t.Fatalf("packetResultCode(%d): expected ErrMalformedPacket, got %v", code, err)
}
}

// A field whose Value has the wrong Go type must produce a
// malformed-packet error, never a panic.
Expand Down
Loading