mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-05-04 10:00:10 -05:00
Bump go-ldap to latest release
To be able to build with latest reva again
This commit is contained in:
+186
-3
@@ -5,9 +5,12 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"os"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
)
|
||||
@@ -352,13 +355,22 @@ func readPacket(reader io.Reader) (*Packet, int, error) {
|
||||
if MaxPacketLengthBytes > 0 && int64(length) > MaxPacketLengthBytes {
|
||||
return nil, read, fmt.Errorf("length %d greater than maximum %d", length, MaxPacketLengthBytes)
|
||||
}
|
||||
content := make([]byte, length)
|
||||
|
||||
var content []byte
|
||||
if length > 0 {
|
||||
_, err := io.ReadFull(reader, content)
|
||||
// Read the content and limit it to the parsed length.
|
||||
// If the content is less than the length, we return an EOF error.
|
||||
content, err = ioutil.ReadAll(io.LimitReader(reader, int64(length)))
|
||||
if err == nil && len(content) < int(length) {
|
||||
err = io.EOF
|
||||
}
|
||||
if err != nil {
|
||||
return nil, read, unexpectedEOF(err)
|
||||
}
|
||||
read += length
|
||||
read += len(content)
|
||||
} else {
|
||||
// If length == 0, we set the ByteValue to an empty slice
|
||||
content = make([]byte, 0)
|
||||
}
|
||||
|
||||
if p.ClassType == ClassUniversal {
|
||||
@@ -381,6 +393,10 @@ func readPacket(reader io.Reader) (*Packet, int, error) {
|
||||
p.Value = DecodeString(content)
|
||||
case TagNULL:
|
||||
case TagObjectIdentifier:
|
||||
oid, err := parseObjectIdentifier(content)
|
||||
if err == nil {
|
||||
p.Value = OIDToString(oid)
|
||||
}
|
||||
case TagObjectDescriptor:
|
||||
case TagExternal:
|
||||
case TagRealFloat:
|
||||
@@ -396,6 +412,10 @@ func readPacket(reader io.Reader) (*Packet, int, error) {
|
||||
p.Value = val
|
||||
}
|
||||
case TagRelativeOID:
|
||||
oid, err := parseObjectIdentifier(content)
|
||||
if err == nil {
|
||||
p.Value = OIDToString(oid)
|
||||
}
|
||||
case TagSequence:
|
||||
case TagSet:
|
||||
case TagNumericString:
|
||||
@@ -623,3 +643,166 @@ func NewReal(classType Class, tagType Type, tag Tag, value interface{}, descript
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func NewOID(classType Class, tagType Type, tag Tag, value interface{}, description string) *Packet {
|
||||
p := Encode(classType, tagType, tag, nil, description)
|
||||
|
||||
switch v := value.(type) {
|
||||
case string:
|
||||
encoded, err := encodeOID(v)
|
||||
if err != nil {
|
||||
fmt.Printf("failed writing %v", err)
|
||||
return nil
|
||||
}
|
||||
p.Value = v
|
||||
p.Data.Write(encoded)
|
||||
// TODO: support []int already ?
|
||||
default:
|
||||
panic(fmt.Sprintf("Invalid type %T, expected float{64|32}", v))
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
// encodeOID takes a string representation of an OID and returns its DER-encoded byte slice along with any error.
|
||||
func encodeOID(oidString string) ([]byte, error) {
|
||||
// Convert the string representation to an asn1.ObjectIdentifier
|
||||
parts := strings.Split(oidString, ".")
|
||||
oid := make([]int, len(parts))
|
||||
for i, part := range parts {
|
||||
var val int
|
||||
if _, err := fmt.Sscanf(part, "%d", &val); err != nil {
|
||||
return nil, fmt.Errorf("invalid OID part '%s': %w", part, err)
|
||||
}
|
||||
oid[i] = val
|
||||
}
|
||||
if len(oid) < 2 || oid[0] > 2 || (oid[0] < 2 && oid[1] >= 40) {
|
||||
panic(fmt.Sprintf("invalid object identifier % d", oid)) // TODO: not elegant
|
||||
}
|
||||
encoded := make([]byte, 0)
|
||||
|
||||
encoded = appendBase128Int(encoded[:0], int64(oid[0]*40+oid[1]))
|
||||
for i := 2; i < len(oid); i++ {
|
||||
encoded = appendBase128Int(encoded, int64(oid[i]))
|
||||
}
|
||||
|
||||
return encoded, nil
|
||||
}
|
||||
|
||||
func appendBase128Int(dst []byte, n int64) []byte {
|
||||
l := base128IntLength(n)
|
||||
|
||||
for i := l - 1; i >= 0; i-- {
|
||||
o := byte(n >> uint(i*7))
|
||||
o &= 0x7f
|
||||
if i != 0 {
|
||||
o |= 0x80
|
||||
}
|
||||
|
||||
dst = append(dst, o)
|
||||
}
|
||||
|
||||
return dst
|
||||
}
|
||||
func base128IntLength(n int64) int {
|
||||
if n == 0 {
|
||||
return 1
|
||||
}
|
||||
|
||||
l := 0
|
||||
for i := n; i > 0; i >>= 7 {
|
||||
l++
|
||||
}
|
||||
|
||||
return l
|
||||
}
|
||||
|
||||
func OIDToString(oi []int) string {
|
||||
var s strings.Builder
|
||||
s.Grow(32)
|
||||
|
||||
buf := make([]byte, 0, 19)
|
||||
for i, v := range oi {
|
||||
if i > 0 {
|
||||
s.WriteByte('.')
|
||||
}
|
||||
s.Write(strconv.AppendInt(buf, int64(v), 10))
|
||||
}
|
||||
|
||||
return s.String()
|
||||
}
|
||||
|
||||
// parseObjectIdentifier parses an OBJECT IDENTIFIER from the given bytes and
|
||||
// returns it. An object identifier is a sequence of variable length integers
|
||||
// that are assigned in a hierarchy.
|
||||
func parseObjectIdentifier(bytes []byte) (s []int, err error) {
|
||||
if len(bytes) == 0 {
|
||||
err = fmt.Errorf("zero length OBJECT IDENTIFIER")
|
||||
return
|
||||
}
|
||||
|
||||
// In the worst case, we get two elements from the first byte (which is
|
||||
// encoded differently) and then every varint is a single byte long.
|
||||
s = make([]int, len(bytes)+1)
|
||||
|
||||
// The first varint is 40*value1 + value2:
|
||||
// According to this packing, value1 can take the values 0, 1 and 2 only.
|
||||
// When value1 = 0 or value1 = 1, then value2 is <= 39. When value1 = 2,
|
||||
// then there are no restrictions on value2.
|
||||
v, offset, err := parseBase128Int(bytes, 0)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if v < 80 {
|
||||
s[0] = v / 40
|
||||
s[1] = v % 40
|
||||
} else {
|
||||
s[0] = 2
|
||||
s[1] = v - 80
|
||||
}
|
||||
|
||||
i := 2
|
||||
for ; offset < len(bytes); i++ {
|
||||
v, offset, err = parseBase128Int(bytes, offset)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
s[i] = v
|
||||
}
|
||||
s = s[0:i]
|
||||
return
|
||||
}
|
||||
|
||||
// parseBase128Int parses a base-128 encoded int from the given offset in the
|
||||
// given byte slice. It returns the value and the new offset.
|
||||
func parseBase128Int(bytes []byte, initOffset int) (ret, offset int, err error) {
|
||||
offset = initOffset
|
||||
var ret64 int64
|
||||
for shifted := 0; offset < len(bytes); shifted++ {
|
||||
// 5 * 7 bits per byte == 35 bits of data
|
||||
// Thus the representation is either non-minimal or too large for an int32
|
||||
if shifted == 5 {
|
||||
err = fmt.Errorf("base 128 integer too large")
|
||||
return
|
||||
}
|
||||
ret64 <<= 7
|
||||
b := bytes[offset]
|
||||
// integers should be minimally encoded, so the leading octet should
|
||||
// never be 0x80
|
||||
if shifted == 0 && b == 0x80 {
|
||||
err = fmt.Errorf("integer is not minimally encoded")
|
||||
return
|
||||
}
|
||||
ret64 |= int64(b & 0x7f)
|
||||
offset++
|
||||
if b&0x80 == 0 {
|
||||
ret = int(ret64)
|
||||
// Ensure that the returned value fits in an int on all platforms
|
||||
if ret64 > math.MaxInt32 {
|
||||
err = fmt.Errorf("base 128 integer too large")
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
err = fmt.Errorf("truncated base 128 integer")
|
||||
return
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2011-2015 Michael Mitton (mmitton@gmail.com)
|
||||
Portions copyright (c) 2015-2016 go-ldap Authors
|
||||
Portions copyright (c) 2015-2024 go-ldap Authors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
+1
@@ -28,6 +28,7 @@ type Client interface {
|
||||
Modify(*ModifyRequest) error
|
||||
ModifyDN(*ModifyDNRequest) error
|
||||
ModifyWithResult(*ModifyRequest) (*ModifyResult, error)
|
||||
Extended(*ExtendedRequest) (*ExtendedResponse, error)
|
||||
|
||||
Compare(dn, attribute, value string) (bool, error)
|
||||
PasswordModify(*PasswordModifyRequest) (*PasswordModifyResult, error)
|
||||
|
||||
+1
-1
@@ -220,7 +220,7 @@ func GetLDAPError(packet *ber.Packet) error {
|
||||
return &Error{
|
||||
ResultCode: resultCode,
|
||||
MatchedDN: response.Children[1].Value.(string),
|
||||
Err: fmt.Errorf("%s", response.Children[2].Value.(string)),
|
||||
Err: fmt.Errorf("%v", response.Children[2].Value),
|
||||
Packet: packet,
|
||||
}
|
||||
}
|
||||
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
package ldap
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
ber "github.com/go-asn1-ber/asn1-ber"
|
||||
)
|
||||
|
||||
// ExtendedRequest represents an extended request to send to the server
|
||||
// See: https://www.rfc-editor.org/rfc/rfc4511#section-4.12
|
||||
type ExtendedRequest struct {
|
||||
// ExtendedRequest ::= [APPLICATION 23] SEQUENCE {
|
||||
// requestName [0] LDAPOID,
|
||||
// requestValue [1] OCTET STRING OPTIONAL }
|
||||
|
||||
Name string
|
||||
Value *ber.Packet
|
||||
Controls []Control
|
||||
}
|
||||
|
||||
// NewExtendedRequest returns a new ExtendedRequest. The value can be
|
||||
// nil depending on the type of request
|
||||
func NewExtendedRequest(name string, value *ber.Packet) *ExtendedRequest {
|
||||
return &ExtendedRequest{
|
||||
Name: name,
|
||||
Value: value,
|
||||
}
|
||||
}
|
||||
|
||||
func (er ExtendedRequest) appendTo(envelope *ber.Packet) error {
|
||||
pkt := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationExtendedRequest, nil, "Extended Request")
|
||||
pkt.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, ber.TagEOC, er.Name, "Extended Request Name"))
|
||||
if er.Value != nil {
|
||||
pkt.AppendChild(er.Value)
|
||||
}
|
||||
envelope.AppendChild(pkt)
|
||||
if len(er.Controls) > 0 {
|
||||
envelope.AppendChild(encodeControls(er.Controls))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ExtendedResponse represents the response from the directory server
|
||||
// after sending an extended request
|
||||
// See: https://www.rfc-editor.org/rfc/rfc4511#section-4.12
|
||||
type ExtendedResponse struct {
|
||||
// ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
|
||||
// COMPONENTS OF LDAPResult,
|
||||
// responseName [10] LDAPOID OPTIONAL,
|
||||
// responseValue [11] OCTET STRING OPTIONAL }
|
||||
|
||||
Name string
|
||||
Value *ber.Packet
|
||||
Controls []Control
|
||||
}
|
||||
|
||||
// Extended performs an extended request. The resulting
|
||||
// ExtendedResponse may return a value in the form of a *ber.Packet
|
||||
func (l *Conn) Extended(er *ExtendedRequest) (*ExtendedResponse, error) {
|
||||
msgCtx, err := l.doRequest(er)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer l.finishMessage(msgCtx)
|
||||
|
||||
packet, err := l.readPacket(msgCtx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = GetLDAPError(packet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(packet.Children[1].Children) < 4 {
|
||||
return nil, fmt.Errorf(
|
||||
"ldap: malformed extended response: expected 4 children, got %d",
|
||||
len(packet.Children),
|
||||
)
|
||||
}
|
||||
|
||||
response := &ExtendedResponse{
|
||||
Name: packet.Children[1].Children[3].Data.String(),
|
||||
Controls: make([]Control, 0),
|
||||
}
|
||||
|
||||
if len(packet.Children) == 3 {
|
||||
for _, child := range packet.Children[2].Children {
|
||||
decodedChild, decodeErr := DecodeControl(child)
|
||||
if decodeErr != nil {
|
||||
return nil, fmt.Errorf("failed to decode child control: %s", decodeErr)
|
||||
}
|
||||
response.Controls = append(response.Controls, decodedChild)
|
||||
}
|
||||
}
|
||||
|
||||
if len(packet.Children[1].Children) == 5 {
|
||||
response.Value = packet.Children[1].Children[4]
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
+5
-1
@@ -579,9 +579,13 @@ func (l *Conn) Search(searchRequest *SearchRequest) (*SearchResult, error) {
|
||||
return result, ErrSizeLimitExceeded
|
||||
}
|
||||
|
||||
attr := make([]*ber.Packet, 0)
|
||||
if len(packet.Children[1].Children) > 1 {
|
||||
attr = packet.Children[1].Children[1].Children
|
||||
}
|
||||
entry := &Entry{
|
||||
DN: packet.Children[1].Children[0].Value.(string),
|
||||
Attributes: unpackAttributes(packet.Children[1].Children[1].Children),
|
||||
Attributes: unpackAttributes(attr),
|
||||
}
|
||||
result.Entries = append(result.Entries, entry)
|
||||
case 5:
|
||||
|
||||
Reference in New Issue
Block a user