From 3d961acaba72793519010ba3a91ea9eff4a10be6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 Sep 2023 10:59:23 +0000 Subject: [PATCH] Bump github.com/go-ldap/ldap/v3 from 3.4.5 to 3.4.6 Bumps [github.com/go-ldap/ldap/v3](https://github.com/go-ldap/ldap) from 3.4.5 to 3.4.6. - [Release notes](https://github.com/go-ldap/ldap/releases) - [Commits](https://github.com/go-ldap/ldap/compare/v3.4.5...v3.4.6) --- updated-dependencies: - dependency-name: github.com/go-ldap/ldap/v3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 4 +- go.sum | 8 +- vendor/github.com/go-asn1-ber/asn1-ber/ber.go | 29 +- .../go-asn1-ber/asn1-ber/identifier.go | 2 +- .../github.com/go-asn1-ber/asn1-ber/length.go | 4 +- .../github.com/go-asn1-ber/asn1-ber/real.go | 6 + .../github.com/go-asn1-ber/asn1-ber/util.go | 10 +- vendor/github.com/go-ldap/ldap/v3/client.go | 4 + vendor/github.com/go-ldap/ldap/v3/conn.go | 25 +- vendor/github.com/go-ldap/ldap/v3/control.go | 522 ++++++++++++++++-- vendor/github.com/go-ldap/ldap/v3/error.go | 26 +- vendor/github.com/go-ldap/ldap/v3/ldap.go | 2 + vendor/github.com/go-ldap/ldap/v3/response.go | 207 +++++++ vendor/github.com/go-ldap/ldap/v3/search.go | 108 +++- vendor/modules.txt | 4 +- 15 files changed, 848 insertions(+), 113 deletions(-) create mode 100644 vendor/github.com/go-ldap/ldap/v3/response.go diff --git a/go.mod b/go.mod index eb5c00448eb..64b40de29e0 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,7 @@ require ( github.com/go-chi/chi/v5 v5.0.10 github.com/go-chi/cors v1.2.1 github.com/go-chi/render v1.0.3 - github.com/go-ldap/ldap/v3 v3.4.5 + github.com/go-ldap/ldap/v3 v3.4.6 github.com/go-ldap/ldif v0.0.0-20200320164324-fd88d9b715b3 github.com/go-micro/plugins/v4/client/grpc v1.2.1 github.com/go-micro/plugins/v4/logger/zerolog v1.2.0 @@ -180,7 +180,7 @@ require ( github.com/gdexlab/go-render v1.0.1 // indirect github.com/ghodss/yaml v1.0.0 // indirect github.com/go-acme/lego/v4 v4.4.0 // indirect - github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect + github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect github.com/go-git/gcfg v1.5.0 // indirect github.com/go-git/go-billy/v5 v5.3.1 // indirect github.com/go-git/go-git/v5 v5.4.2 // indirect diff --git a/go.sum b/go.sum index 0b08fc580da..365c31b4257 100644 --- a/go.sum +++ b/go.sum @@ -1120,8 +1120,8 @@ github.com/go-acme/lego/v4 v4.4.0 h1:uHhU5LpOYQOdp3aDU+XY2bajseu8fuExphTL1Ss6/Fc github.com/go-acme/lego/v4 v4.4.0/go.mod h1:l3+tFUFZb590dWcqhWZegynUthtaHJbG2fevUpoOOE0= github.com/go-asn1-ber/asn1-ber v1.3.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= github.com/go-asn1-ber/asn1-ber v1.4.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= -github.com/go-asn1-ber/asn1-ber v1.5.4 h1:vXT6d/FNDiELJnLb6hGNa309LMsrCoYFvpwHDF0+Y1A= -github.com/go-asn1-ber/asn1-ber v1.5.4/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-asn1-ber/asn1-ber v1.5.5 h1:MNHlNMBDgEKD4TcKr36vQN68BA00aDfjIt3/bD50WnA= +github.com/go-asn1-ber/asn1-ber v1.5.5/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= github.com/go-chi/chi v4.0.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= github.com/go-chi/chi/v5 v5.0.8/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk= @@ -1160,8 +1160,8 @@ github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBj github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U= github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81/go.mod h1:SX0U8uGpxhq9o2S/CELCSUxEWWAuoCUcVCQWv7G2OCk= github.com/go-ldap/ldap/v3 v3.1.7/go.mod h1:5Zun81jBTabRaI8lzN7E1JjyEl1g6zI6u9pd8luAK4Q= -github.com/go-ldap/ldap/v3 v3.4.5 h1:ekEKmaDrpvR2yf5Nc/DClsGG9lAmdDixe44mLzlW5r8= -github.com/go-ldap/ldap/v3 v3.4.5/go.mod h1:bMGIq3AGbytbaMwf8wdv5Phdxz0FWHTIYMSzyrYgnQs= +github.com/go-ldap/ldap/v3 v3.4.6 h1:ert95MdbiG7aWo/oPYp9btL3KJlMPKnP58r09rI8T+A= +github.com/go-ldap/ldap/v3 v3.4.6/go.mod h1:IGMQANNtxpsOzj7uUAMjpGBaOVTC4DYyIy8VsTdxmtc= github.com/go-ldap/ldif v0.0.0-20200320164324-fd88d9b715b3 h1:sfz1YppV05y4sYaW7kXZtrocU/+vimnIWt4cxAYh7+o= github.com/go-ldap/ldif v0.0.0-20200320164324-fd88d9b715b3/go.mod h1:ZXFhGda43Z2TVbfGZefXyMJzsDHhCh0go3bZUcwTx7o= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= diff --git a/vendor/github.com/go-asn1-ber/asn1-ber/ber.go b/vendor/github.com/go-asn1-ber/asn1-ber/ber.go index 4fd7a66e18f..bafa78631a5 100644 --- a/vendor/github.com/go-asn1-ber/asn1-ber/ber.go +++ b/vendor/github.com/go-asn1-ber/asn1-ber/ber.go @@ -170,12 +170,10 @@ func PrintPacket(p *Packet) { printPacket(os.Stdout, p, 0, false) } -func printPacket(out io.Writer, p *Packet, indent int, printBytes bool) { - indentStr := "" - - for len(indentStr) != indent { - indentStr += " " - } +// Return a string describing packet content. This is not recursive, +// If the packet is a sequence, use `printPacket()`, or browse +// sequence yourself. +func DescribePacket(p *Packet) string { classStr := ClassMap[p.ClassType] @@ -194,7 +192,17 @@ func printPacket(out io.Writer, p *Packet, indent int, printBytes bool) { description = p.Description + ": " } - _, _ = fmt.Fprintf(out, "%s%s(%s, %s, %s) Len=%d %q\n", indentStr, description, classStr, tagTypeStr, tagStr, p.Data.Len(), value) + return fmt.Sprintf("%s(%s, %s, %s) Len=%d %q", description, classStr, tagTypeStr, tagStr, p.Data.Len(), value) +} + +func printPacket(out io.Writer, p *Packet, indent int, printBytes bool) { + indentStr := "" + + for len(indentStr) != indent { + indentStr += " " + } + + _, _ = fmt.Fprintf(out, "%s%s\n", indentStr, DescribePacket(p)) if printBytes { PrintBytes(out, p.Bytes(), indentStr) @@ -317,7 +325,7 @@ func readPacket(reader io.Reader) (*Packet, int, error) { // Read the next packet child, r, err := readPacket(reader) if err != nil { - return nil, read, err + return nil, read, unexpectedEOF(err) } contentRead += r read += r @@ -348,10 +356,7 @@ func readPacket(reader io.Reader) (*Packet, int, error) { if length > 0 { _, err := io.ReadFull(reader, content) if err != nil { - if err == io.EOF { - return nil, read, io.ErrUnexpectedEOF - } - return nil, read, err + return nil, read, unexpectedEOF(err) } read += length } diff --git a/vendor/github.com/go-asn1-ber/asn1-ber/identifier.go b/vendor/github.com/go-asn1-ber/asn1-ber/identifier.go index e8c435749a6..c501d8190c0 100644 --- a/vendor/github.com/go-asn1-ber/asn1-ber/identifier.go +++ b/vendor/github.com/go-asn1-ber/asn1-ber/identifier.go @@ -37,7 +37,7 @@ func readIdentifier(reader io.Reader) (Identifier, int, error) { if Debug { fmt.Printf("error reading high-tag-number tag byte %d: %v\n", tagBytes, err) } - return Identifier{}, read, err + return Identifier{}, read, unexpectedEOF(err) } tagBytes++ read++ diff --git a/vendor/github.com/go-asn1-ber/asn1-ber/length.go b/vendor/github.com/go-asn1-ber/asn1-ber/length.go index 9cc195d0bdf..2c81cc3fd29 100644 --- a/vendor/github.com/go-asn1-ber/asn1-ber/length.go +++ b/vendor/github.com/go-asn1-ber/asn1-ber/length.go @@ -13,7 +13,7 @@ func readLength(reader io.Reader) (length int, read int, err error) { if Debug { fmt.Printf("error reading length byte: %v\n", err) } - return 0, 0, err + return 0, 0, unexpectedEOF(err) } read++ @@ -47,7 +47,7 @@ func readLength(reader io.Reader) (length int, read int, err error) { if Debug { fmt.Printf("error reading long-form length byte %d: %v\n", i, err) } - return 0, read, err + return 0, read, unexpectedEOF(err) } read++ diff --git a/vendor/github.com/go-asn1-ber/asn1-ber/real.go b/vendor/github.com/go-asn1-ber/asn1-ber/real.go index 610a003a734..9f637a572a2 100644 --- a/vendor/github.com/go-asn1-ber/asn1-ber/real.go +++ b/vendor/github.com/go-asn1-ber/asn1-ber/real.go @@ -89,12 +89,18 @@ func parseBinaryFloat(v []byte) (float64, error) { case 0x02: expLen = 3 case 0x03: + if len(v) < 2 { + return 0.0, errors.New("invalid data") + } expLen = int(v[0]) if expLen > 8 { return 0.0, errors.New("too big value of exponent") } v = v[1:] } + if expLen > len(v) { + return 0.0, errors.New("too big value of exponent") + } buf, v = v[:expLen], v[expLen:] exponent, err := ParseInt64(buf) if err != nil { diff --git a/vendor/github.com/go-asn1-ber/asn1-ber/util.go b/vendor/github.com/go-asn1-ber/asn1-ber/util.go index 14dc87d7c92..da45e9fa55b 100644 --- a/vendor/github.com/go-asn1-ber/asn1-ber/util.go +++ b/vendor/github.com/go-asn1-ber/asn1-ber/util.go @@ -6,14 +6,18 @@ func readByte(reader io.Reader) (byte, error) { bytes := make([]byte, 1) _, err := io.ReadFull(reader, bytes) if err != nil { - if err == io.EOF { - return 0, io.ErrUnexpectedEOF - } return 0, err } return bytes[0], nil } +func unexpectedEOF(err error) error { + if err == io.EOF { + return io.ErrUnexpectedEOF + } + return err +} + func isEOCPacket(p *Packet) bool { return p != nil && p.Tag == TagEOC && diff --git a/vendor/github.com/go-ldap/ldap/v3/client.go b/vendor/github.com/go-ldap/ldap/v3/client.go index b438d254b28..ed96e840aa6 100644 --- a/vendor/github.com/go-ldap/ldap/v3/client.go +++ b/vendor/github.com/go-ldap/ldap/v3/client.go @@ -1,6 +1,7 @@ package ldap import ( + "context" "crypto/tls" "time" ) @@ -32,6 +33,9 @@ type Client interface { PasswordModify(*PasswordModifyRequest) (*PasswordModifyResult, error) Search(*SearchRequest) (*SearchResult, error) + SearchAsync(ctx context.Context, searchRequest *SearchRequest, bufferSize int) Response SearchWithPaging(searchRequest *SearchRequest, pagingSize uint32) (*SearchResult, error) DirSync(searchRequest *SearchRequest, flags, maxAttrCount int64, cookie []byte) (*SearchResult, error) + DirSyncAsync(ctx context.Context, searchRequest *SearchRequest, bufferSize int, flags, maxAttrCount int64, cookie []byte) Response + Syncrepl(ctx context.Context, searchRequest *SearchRequest, bufferSize int, mode ControlSyncRequestMode, cookie []byte, reloadHint bool) Response } diff --git a/vendor/github.com/go-ldap/ldap/v3/conn.go b/vendor/github.com/go-ldap/ldap/v3/conn.go index 3ed8088312b..6d08362145b 100644 --- a/vendor/github.com/go-ldap/ldap/v3/conn.go +++ b/vendor/github.com/go-ldap/ldap/v3/conn.go @@ -288,9 +288,9 @@ func (l *Conn) Close() (err error) { l.chanMessage <- &messagePacket{Op: MessageQuit} timeoutCtx := context.Background() - if l.requestTimeout > 0 { + if l.getTimeout() > 0 { var cancelFunc context.CancelFunc - timeoutCtx, cancelFunc = context.WithTimeout(timeoutCtx, time.Duration(l.requestTimeout)) + timeoutCtx, cancelFunc = context.WithTimeout(timeoutCtx, time.Duration(l.getTimeout())) defer cancelFunc() } select { @@ -316,6 +316,10 @@ func (l *Conn) SetTimeout(timeout time.Duration) { atomic.StoreInt64(&l.requestTimeout, int64(timeout)) } +func (l *Conn) getTimeout() int64 { + return atomic.LoadInt64(&l.requestTimeout) +} + // Returns the next available messageID func (l *Conn) nextMessageID() int64 { if messageID, ok := <-l.chanMessageID; ok { @@ -325,8 +329,10 @@ func (l *Conn) nextMessageID() int64 { } // GetLastError returns the last recorded error from goroutines like processMessages and reader. -// // Only the last recorded error will be returned. +// Only the last recorded error will be returned. func (l *Conn) GetLastError() error { + l.messageMutex.Lock() + defer l.messageMutex.Unlock() return l.err } @@ -484,7 +490,7 @@ func (l *Conn) processMessages() { // If we are closing due to an error, inform anyone who // is waiting about the error. if l.IsClosing() && l.closeErr.Load() != nil { - msgCtx.sendResponse(&PacketResponse{Error: l.closeErr.Load().(error)}, time.Duration(l.requestTimeout)) + msgCtx.sendResponse(&PacketResponse{Error: l.closeErr.Load().(error)}, time.Duration(l.getTimeout())) } l.Debug.Printf("Closing channel for MessageID %d", messageID) close(msgCtx.responses) @@ -512,7 +518,7 @@ func (l *Conn) processMessages() { _, err := l.conn.Write(buf) if err != nil { l.Debug.Printf("Error Sending Message: %s", err.Error()) - message.Context.sendResponse(&PacketResponse{Error: fmt.Errorf("unable to send request: %s", err)}, time.Duration(l.requestTimeout)) + message.Context.sendResponse(&PacketResponse{Error: fmt.Errorf("unable to send request: %s", err)}, time.Duration(l.getTimeout())) close(message.Context.responses) break } @@ -522,9 +528,10 @@ func (l *Conn) processMessages() { l.messageContexts[message.MessageID] = message.Context // Add timeout if defined - if l.requestTimeout > 0 { + requestTimeout := l.getTimeout() + if requestTimeout > 0 { go func() { - timer := time.NewTimer(time.Duration(l.requestTimeout)) + timer := time.NewTimer(time.Duration(requestTimeout)) defer func() { if err := recover(); err != nil { l.err = fmt.Errorf("ldap: recovered panic in RequestTimeout: %v", err) @@ -547,7 +554,7 @@ func (l *Conn) processMessages() { case MessageResponse: l.Debug.Printf("Receiving message %d", message.MessageID) if msgCtx, ok := l.messageContexts[message.MessageID]; ok { - msgCtx.sendResponse(&PacketResponse{message.Packet, nil}, time.Duration(l.requestTimeout)) + msgCtx.sendResponse(&PacketResponse{message.Packet, nil}, time.Duration(l.getTimeout())) } else { l.err = fmt.Errorf("ldap: received unexpected message %d, %v", message.MessageID, l.IsClosing()) l.Debug.PrintPacket(message.Packet) @@ -557,7 +564,7 @@ func (l *Conn) processMessages() { // All reads will return immediately if msgCtx, ok := l.messageContexts[message.MessageID]; ok { l.Debug.Printf("Receiving message timeout for %d", message.MessageID) - msgCtx.sendResponse(&PacketResponse{message.Packet, NewError(ErrorNetwork, errors.New("ldap: connection timed out"))}, time.Duration(l.requestTimeout)) + msgCtx.sendResponse(&PacketResponse{message.Packet, NewError(ErrorNetwork, errors.New("ldap: connection timed out"))}, time.Duration(l.getTimeout())) delete(l.messageContexts, message.MessageID) close(msgCtx.responses) } diff --git a/vendor/github.com/go-ldap/ldap/v3/control.go b/vendor/github.com/go-ldap/ldap/v3/control.go index 0be697e220e..60453deb13b 100644 --- a/vendor/github.com/go-ldap/ldap/v3/control.go +++ b/vendor/github.com/go-ldap/ldap/v3/control.go @@ -5,6 +5,7 @@ import ( "strconv" ber "github.com/go-asn1-ber/asn1-ber" + "github.com/google/uuid" ) const ( @@ -36,6 +37,15 @@ const ( ControlTypeMicrosoftServerLinkTTL = "1.2.840.113556.1.4.2309" // ControlTypeDirSync - Active Directory DirSync - https://msdn.microsoft.com/en-us/library/aa366978(v=vs.85).aspx ControlTypeDirSync = "1.2.840.113556.1.4.841" + + // ControlTypeSyncRequest - https://www.ietf.org/rfc/rfc4533.txt + ControlTypeSyncRequest = "1.3.6.1.4.1.4203.1.9.1.1" + // ControlTypeSyncState - https://www.ietf.org/rfc/rfc4533.txt + ControlTypeSyncState = "1.3.6.1.4.1.4203.1.9.1.2" + // ControlTypeSyncDone - https://www.ietf.org/rfc/rfc4533.txt + ControlTypeSyncDone = "1.3.6.1.4.1.4203.1.9.1.3" + // ControlTypeSyncInfo - https://www.ietf.org/rfc/rfc4533.txt + ControlTypeSyncInfo = "1.3.6.1.4.1.4203.1.9.1.4" ) // Flags for DirSync control @@ -58,6 +68,10 @@ var ControlTypeMap = map[string]string{ ControlTypeServerSideSorting: "Server Side Sorting Request - LDAP Control Extension for Server Side Sorting of Search Results (RFC2891)", ControlTypeServerSideSortingResult: "Server Side Sorting Results - LDAP Control Extension for Server Side Sorting of Search Results (RFC2891)", ControlTypeDirSync: "DirSync", + ControlTypeSyncRequest: "Sync Request", + ControlTypeSyncState: "Sync State", + ControlTypeSyncDone: "Sync Done", + ControlTypeSyncInfo: "Sync Info", } // Control defines an interface controls provide to encode and describe themselves @@ -390,7 +404,13 @@ func DecodeControl(packet *ber.Packet) (Control, error) { case 2: packet.Children[0].Description = "Control Type (" + ControlTypeMap[ControlType] + ")" - ControlType = packet.Children[0].Value.(string) + if packet.Children[0].Value != nil { + ControlType = packet.Children[0].Value.(string) + } else if packet.Children[0].Data != nil { + ControlType = packet.Children[0].Data.String() + } else { + return nil, fmt.Errorf("not found where to get the control type") + } // Children[1] could be criticality or value (both are optional) // duck-type on whether this is a boolean @@ -514,29 +534,28 @@ func DecodeControl(packet *ber.Packet) (Control, error) { return NewControlServerSideSortingResult(value) case ControlTypeDirSync: value.Description += " (DirSync)" - c := new(ControlDirSync) - if value.Value != nil { - valueChildren, err := ber.DecodePacketErr(value.Data.Bytes()) - if err != nil { - return nil, err - } - value.Data.Truncate(0) - value.Value = nil - value.AppendChild(valueChildren) + return NewResponseControlDirSync(value) + case ControlTypeSyncState: + value.Description += " (Sync State)" + valueChildren, err := ber.DecodePacketErr(value.Data.Bytes()) + if err != nil { + return nil, fmt.Errorf("failed to decode data bytes: %s", err) } - value = value.Children[0] - if len(value.Children) != 3 { // also on initial creation, Cookie is an empty string - return nil, fmt.Errorf("invalid number of children in dirSync control") + return NewControlSyncState(valueChildren) + case ControlTypeSyncDone: + value.Description += " (Sync Done)" + valueChildren, err := ber.DecodePacketErr(value.Data.Bytes()) + if err != nil { + return nil, fmt.Errorf("failed to decode data bytes: %s", err) } - value.Description = "DirSync Control Value" - value.Children[0].Description = "Flags" - value.Children[1].Description = "MaxAttrCnt" - value.Children[2].Description = "Cookie" - c.Flags = value.Children[0].Value.(int64) - c.MaxAttrCnt = value.Children[1].Value.(int64) - c.Cookie = value.Children[2].Data.Bytes() - value.Children[2].Value = c.Cookie - return c, nil + return NewControlSyncDone(valueChildren) + case ControlTypeSyncInfo: + value.Description += " (Sync Info)" + valueChildren, err := ber.DecodePacketErr(value.Data.Bytes()) + if err != nil { + return nil, fmt.Errorf("failed to decode data bytes: %s", err) + } + return NewControlSyncInfo(valueChildren) default: c := new(ControlString) c.ControlType = ControlType @@ -610,18 +629,57 @@ func encodeControls(controls []Control) *ber.Packet { // ControlDirSync implements the control described in https://msdn.microsoft.com/en-us/library/aa366978(v=vs.85).aspx type ControlDirSync struct { - Flags int64 - MaxAttrCnt int64 - Cookie []byte + Criticality bool + Flags int64 + MaxAttrCount int64 + Cookie []byte } -// NewControlDirSync returns a dir sync control +// @deprecated Use NewRequestControlDirSync instead func NewControlDirSync(flags int64, maxAttrCount int64, cookie []byte) *ControlDirSync { + return NewRequestControlDirSync(flags, maxAttrCount, cookie) +} + +// NewRequestControlDirSync returns a dir sync control +func NewRequestControlDirSync( + flags int64, maxAttrCount int64, cookie []byte, +) *ControlDirSync { return &ControlDirSync{ - Flags: flags, - MaxAttrCnt: maxAttrCount, - Cookie: cookie, + Criticality: true, + Flags: flags, + MaxAttrCount: maxAttrCount, + Cookie: cookie, + } +} + +// NewResponseControlDirSync returns a dir sync control +func NewResponseControlDirSync(value *ber.Packet) (*ControlDirSync, error) { + if value.Value != nil { + valueChildren, err := ber.DecodePacketErr(value.Data.Bytes()) + if err != nil { + return nil, fmt.Errorf("failed to decode data bytes: %s", err) + } + value.Data.Truncate(0) + value.Value = nil + value.AppendChild(valueChildren) + } + child := value.Children[0] + if len(child.Children) != 3 { // also on initial creation, Cookie is an empty string + return nil, fmt.Errorf("invalid number of children in dirSync control") } + child.Description = "DirSync Control Value" + child.Children[0].Description = "Flags" + child.Children[1].Description = "MaxAttrCount" + child.Children[2].Description = "Cookie" + + cookie := child.Children[2].Data.Bytes() + child.Children[2].Value = cookie + return &ControlDirSync{ + Criticality: true, + Flags: child.Children[0].Value.(int64), + MaxAttrCount: child.Children[1].Value.(int64), + Cookie: cookie, + }, nil } // GetControlType returns the OID @@ -631,28 +689,33 @@ func (c *ControlDirSync) GetControlType() string { // String returns a human-readable description func (c *ControlDirSync) String() string { - return fmt.Sprintf("ControlType: %s (%q), Criticality: true, ControlValue: Flags: %d, MaxAttrCnt: %d", ControlTypeMap[ControlTypeDirSync], ControlTypeDirSync, c.Flags, c.MaxAttrCnt) + return fmt.Sprintf( + "ControlType: %s (%q) Criticality: %t ControlValue: Flags: %d MaxAttrCount: %d", + ControlTypeMap[ControlTypeDirSync], + ControlTypeDirSync, + c.Criticality, + c.Flags, + c.MaxAttrCount, + ) } // Encode returns the ber packet representation func (c *ControlDirSync) Encode() *ber.Packet { + cookie := ber.Encode(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, "", "Cookie") + if len(c.Cookie) != 0 { + cookie.Value = c.Cookie + cookie.Data.Write(c.Cookie) + } + packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Control") packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, ControlTypeDirSync, "Control Type ("+ControlTypeMap[ControlTypeDirSync]+")")) - packet.AppendChild(ber.NewBoolean(ber.ClassUniversal, ber.TypePrimitive, ber.TagBoolean, true, "Criticality")) // must be true always + packet.AppendChild(ber.NewBoolean(ber.ClassUniversal, ber.TypePrimitive, ber.TagBoolean, c.Criticality, "Criticality")) // must be true always val := ber.Encode(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, nil, "Control Value (DirSync)") - seq := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "DirSync Control Value") seq.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, int64(c.Flags), "Flags")) - seq.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, int64(c.MaxAttrCnt), "MaxAttrCount")) - - cookie := ber.Encode(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, "", "Cookie") - if len(c.Cookie) != 0 { - cookie.Value = c.Cookie - cookie.Data.Write(c.Cookie) - } + seq.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, int64(c.MaxAttrCount), "MaxAttrCount")) seq.AppendChild(cookie) - val.AppendChild(seq) packet.AppendChild(val) @@ -850,3 +913,382 @@ func (c *ControlServerSideSortingResult) String() string { c.Result, ) } + +// Mode for ControlTypeSyncRequest +type ControlSyncRequestMode int64 + +const ( + SyncRequestModeRefreshOnly ControlSyncRequestMode = 1 + SyncRequestModeRefreshAndPersist ControlSyncRequestMode = 3 +) + +// ControlSyncRequest implements the Sync Request Control described in https://www.ietf.org/rfc/rfc4533.txt +type ControlSyncRequest struct { + Criticality bool + Mode ControlSyncRequestMode + Cookie []byte + ReloadHint bool +} + +func NewControlSyncRequest( + mode ControlSyncRequestMode, cookie []byte, reloadHint bool, +) *ControlSyncRequest { + return &ControlSyncRequest{ + Criticality: true, + Mode: mode, + Cookie: cookie, + ReloadHint: reloadHint, + } +} + +// GetControlType returns the OID +func (c *ControlSyncRequest) GetControlType() string { + return ControlTypeSyncRequest +} + +// Encode encodes the control +func (c *ControlSyncRequest) Encode() *ber.Packet { + _mode := int64(c.Mode) + mode := ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, _mode, "Mode") + var cookie *ber.Packet + if len(c.Cookie) > 0 { + cookie = ber.Encode(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, nil, "Cookie") + cookie.Value = c.Cookie + cookie.Data.Write(c.Cookie) + } + reloadHint := ber.NewBoolean(ber.ClassUniversal, ber.TypePrimitive, ber.TagBoolean, c.ReloadHint, "Reload Hint") + + packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Control") + packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, ControlTypeSyncRequest, "Control Type ("+ControlTypeMap[ControlTypeSyncRequest]+")")) + packet.AppendChild(ber.NewBoolean(ber.ClassUniversal, ber.TypePrimitive, ber.TagBoolean, c.Criticality, "Criticality")) + + val := ber.Encode(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, nil, "Control Value (Sync Request)") + seq := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Sync Request Value") + seq.AppendChild(mode) + if cookie != nil { + seq.AppendChild(cookie) + } + seq.AppendChild(reloadHint) + val.AppendChild(seq) + + packet.AppendChild(val) + return packet +} + +// String returns a human-readable description +func (c *ControlSyncRequest) String() string { + return fmt.Sprintf( + "Control Type: %s (%q) Criticality: %t Mode: %d Cookie: %s ReloadHint: %t", + ControlTypeMap[ControlTypeSyncRequest], + ControlTypeSyncRequest, + c.Criticality, + c.Mode, + string(c.Cookie), + c.ReloadHint, + ) +} + +// State for ControlSyncState +type ControlSyncStateState int64 + +const ( + SyncStatePresent ControlSyncStateState = 0 + SyncStateAdd ControlSyncStateState = 1 + SyncStateModify ControlSyncStateState = 2 + SyncStateDelete ControlSyncStateState = 3 +) + +// ControlSyncState implements the Sync State Control described in https://www.ietf.org/rfc/rfc4533.txt +type ControlSyncState struct { + Criticality bool + State ControlSyncStateState + EntryUUID uuid.UUID + Cookie []byte +} + +func NewControlSyncState(pkt *ber.Packet) (*ControlSyncState, error) { + var ( + state ControlSyncStateState + entryUUID uuid.UUID + cookie []byte + err error + ) + switch len(pkt.Children) { + case 0, 1: + return nil, fmt.Errorf("at least two children are required: %d", len(pkt.Children)) + case 2: + state = ControlSyncStateState(pkt.Children[0].Value.(int64)) + entryUUID, err = uuid.FromBytes(pkt.Children[1].ByteValue) + if err != nil { + return nil, fmt.Errorf("failed to decode uuid: %w", err) + } + case 3: + state = ControlSyncStateState(pkt.Children[0].Value.(int64)) + entryUUID, err = uuid.FromBytes(pkt.Children[1].ByteValue) + if err != nil { + return nil, fmt.Errorf("failed to decode uuid: %w", err) + } + cookie = pkt.Children[2].ByteValue + } + return &ControlSyncState{ + Criticality: false, + State: state, + EntryUUID: entryUUID, + Cookie: cookie, + }, nil +} + +// GetControlType returns the OID +func (c *ControlSyncState) GetControlType() string { + return ControlTypeSyncState +} + +// Encode encodes the control +func (c *ControlSyncState) Encode() *ber.Packet { + return nil +} + +// String returns a human-readable description +func (c *ControlSyncState) String() string { + return fmt.Sprintf( + "Control Type: %s (%q) Criticality: %t State: %d EntryUUID: %s Cookie: %s", + ControlTypeMap[ControlTypeSyncState], + ControlTypeSyncState, + c.Criticality, + c.State, + c.EntryUUID.String(), + string(c.Cookie), + ) +} + +// ControlSyncDone implements the Sync Done Control described in https://www.ietf.org/rfc/rfc4533.txt +type ControlSyncDone struct { + Criticality bool + Cookie []byte + RefreshDeletes bool +} + +func NewControlSyncDone(pkt *ber.Packet) (*ControlSyncDone, error) { + var ( + cookie []byte + refreshDeletes bool + ) + switch len(pkt.Children) { + case 0: + // have nothing to do + case 1: + cookie = pkt.Children[0].ByteValue + case 2: + cookie = pkt.Children[0].ByteValue + refreshDeletes = pkt.Children[1].Value.(bool) + } + return &ControlSyncDone{ + Criticality: false, + Cookie: cookie, + RefreshDeletes: refreshDeletes, + }, nil +} + +// GetControlType returns the OID +func (c *ControlSyncDone) GetControlType() string { + return ControlTypeSyncDone +} + +// Encode encodes the control +func (c *ControlSyncDone) Encode() *ber.Packet { + return nil +} + +// String returns a human-readable description +func (c *ControlSyncDone) String() string { + return fmt.Sprintf( + "Control Type: %s (%q) Criticality: %t Cookie: %s RefreshDeletes: %t", + ControlTypeMap[ControlTypeSyncDone], + ControlTypeSyncDone, + c.Criticality, + string(c.Cookie), + c.RefreshDeletes, + ) +} + +// Tag For ControlSyncInfo +type ControlSyncInfoValue uint64 + +const ( + SyncInfoNewcookie ControlSyncInfoValue = 0 + SyncInfoRefreshDelete ControlSyncInfoValue = 1 + SyncInfoRefreshPresent ControlSyncInfoValue = 2 + SyncInfoSyncIdSet ControlSyncInfoValue = 3 +) + +// ControlSyncInfoNewCookie implements a part of syncInfoValue described in https://www.ietf.org/rfc/rfc4533.txt +type ControlSyncInfoNewCookie struct { + Cookie []byte +} + +// String returns a human-readable description +func (c *ControlSyncInfoNewCookie) String() string { + return fmt.Sprintf( + "NewCookie[Cookie: %s]", + string(c.Cookie), + ) +} + +// ControlSyncInfoRefreshDelete implements a part of syncInfoValue described in https://www.ietf.org/rfc/rfc4533.txt +type ControlSyncInfoRefreshDelete struct { + Cookie []byte + RefreshDone bool +} + +// String returns a human-readable description +func (c *ControlSyncInfoRefreshDelete) String() string { + return fmt.Sprintf( + "RefreshDelete[Cookie: %s RefreshDone: %t]", + string(c.Cookie), + c.RefreshDone, + ) +} + +// ControlSyncInfoRefreshPresent implements a part of syncInfoValue described in https://www.ietf.org/rfc/rfc4533.txt +type ControlSyncInfoRefreshPresent struct { + Cookie []byte + RefreshDone bool +} + +// String returns a human-readable description +func (c *ControlSyncInfoRefreshPresent) String() string { + return fmt.Sprintf( + "RefreshPresent[Cookie: %s RefreshDone: %t]", + string(c.Cookie), + c.RefreshDone, + ) +} + +// ControlSyncInfoSyncIdSet implements a part of syncInfoValue described in https://www.ietf.org/rfc/rfc4533.txt +type ControlSyncInfoSyncIdSet struct { + Cookie []byte + RefreshDeletes bool + SyncUUIDs []uuid.UUID +} + +// String returns a human-readable description +func (c *ControlSyncInfoSyncIdSet) String() string { + return fmt.Sprintf( + "SyncIdSet[Cookie: %s RefreshDeletes: %t SyncUUIDs: %v]", + string(c.Cookie), + c.RefreshDeletes, + c.SyncUUIDs, + ) +} + +// ControlSyncInfo implements the Sync Info Control described in https://www.ietf.org/rfc/rfc4533.txt +type ControlSyncInfo struct { + Criticality bool + Value ControlSyncInfoValue + NewCookie *ControlSyncInfoNewCookie + RefreshDelete *ControlSyncInfoRefreshDelete + RefreshPresent *ControlSyncInfoRefreshPresent + SyncIdSet *ControlSyncInfoSyncIdSet +} + +func NewControlSyncInfo(pkt *ber.Packet) (*ControlSyncInfo, error) { + var ( + cookie []byte + refreshDone = true + refreshDeletes bool + syncUUIDs []uuid.UUID + ) + c := &ControlSyncInfo{Criticality: false} + switch ControlSyncInfoValue(pkt.Identifier.Tag) { + case SyncInfoNewcookie: + c.Value = SyncInfoNewcookie + c.NewCookie = &ControlSyncInfoNewCookie{ + Cookie: pkt.ByteValue, + } + case SyncInfoRefreshDelete: + c.Value = SyncInfoRefreshDelete + switch len(pkt.Children) { + case 0: + // have nothing to do + case 1: + cookie = pkt.Children[0].ByteValue + case 2: + cookie = pkt.Children[0].ByteValue + refreshDone = pkt.Children[1].Value.(bool) + } + c.RefreshDelete = &ControlSyncInfoRefreshDelete{ + Cookie: cookie, + RefreshDone: refreshDone, + } + case SyncInfoRefreshPresent: + c.Value = SyncInfoRefreshPresent + switch len(pkt.Children) { + case 0: + // have nothing to do + case 1: + cookie = pkt.Children[0].ByteValue + case 2: + cookie = pkt.Children[0].ByteValue + refreshDone = pkt.Children[1].Value.(bool) + } + c.RefreshPresent = &ControlSyncInfoRefreshPresent{ + Cookie: cookie, + RefreshDone: refreshDone, + } + case SyncInfoSyncIdSet: + c.Value = SyncInfoSyncIdSet + switch len(pkt.Children) { + case 0: + // have nothing to do + case 1: + cookie = pkt.Children[0].ByteValue + case 2: + cookie = pkt.Children[0].ByteValue + refreshDeletes = pkt.Children[1].Value.(bool) + case 3: + cookie = pkt.Children[0].ByteValue + refreshDeletes = pkt.Children[1].Value.(bool) + syncUUIDs = make([]uuid.UUID, 0, len(pkt.Children[2].Children)) + for _, child := range pkt.Children[2].Children { + u, err := uuid.FromBytes(child.ByteValue) + if err != nil { + return nil, fmt.Errorf("failed to decode uuid: %w", err) + } + syncUUIDs = append(syncUUIDs, u) + } + } + c.SyncIdSet = &ControlSyncInfoSyncIdSet{ + Cookie: cookie, + RefreshDeletes: refreshDeletes, + SyncUUIDs: syncUUIDs, + } + default: + return nil, fmt.Errorf("unknown sync info value: %d", pkt.Identifier.Tag) + } + return c, nil +} + +// GetControlType returns the OID +func (c *ControlSyncInfo) GetControlType() string { + return ControlTypeSyncInfo +} + +// Encode encodes the control +func (c *ControlSyncInfo) Encode() *ber.Packet { + return nil +} + +// String returns a human-readable description +func (c *ControlSyncInfo) String() string { + return fmt.Sprintf( + "Control Type: %s (%q) Criticality: %t Value: %d %s %s %s %s", + ControlTypeMap[ControlTypeSyncInfo], + ControlTypeSyncInfo, + c.Criticality, + c.Value, + c.NewCookie, + c.RefreshDelete, + c.RefreshPresent, + c.SyncIdSet, + ) +} diff --git a/vendor/github.com/go-ldap/ldap/v3/error.go b/vendor/github.com/go-ldap/ldap/v3/error.go index 3cdb7b318c4..3c2559ef700 100644 --- a/vendor/github.com/go-ldap/ldap/v3/error.go +++ b/vendor/github.com/go-ldap/ldap/v3/error.go @@ -192,6 +192,8 @@ func (e *Error) Error() string { return fmt.Sprintf("LDAP Result Code %d %q: %s", e.ResultCode, LDAPResultCodeMap[e.ResultCode], e.Err.Error()) } +func (e *Error) Unwrap() error { return e.Err } + // GetLDAPError creates an Error out of a BER packet representing a LDAPResult // The return is an error object. It can be casted to a Error structure. // This function returns nil if resultCode in the LDAPResult sequence is success(0). @@ -206,15 +208,21 @@ func GetLDAPError(packet *ber.Packet) error { return &Error{ResultCode: ErrorUnexpectedResponse, Err: fmt.Errorf("Empty response in packet"), Packet: packet} } if response.ClassType == ber.ClassApplication && response.TagType == ber.TypeConstructed && len(response.Children) >= 3 { - resultCode := uint16(response.Children[0].Value.(int64)) - if resultCode == 0 { // No error - return nil - } - return &Error{ - ResultCode: resultCode, - MatchedDN: response.Children[1].Value.(string), - Err: fmt.Errorf("%s", response.Children[2].Value.(string)), - Packet: packet, + if ber.Type(response.Children[0].Tag) == ber.Type(ber.TagInteger) || ber.Type(response.Children[0].Tag) == ber.Type(ber.TagEnumerated) { + resultCode := uint16(response.Children[0].Value.(int64)) + if resultCode == 0 { // No error + return nil + } + + if ber.Type(response.Children[1].Tag) == ber.Type(ber.TagOctetString) && + ber.Type(response.Children[2].Tag) == ber.Type(ber.TagOctetString) { + return &Error{ + ResultCode: resultCode, + MatchedDN: response.Children[1].Value.(string), + Err: fmt.Errorf("%s", response.Children[2].Value.(string)), + Packet: packet, + } + } } } } diff --git a/vendor/github.com/go-ldap/ldap/v3/ldap.go b/vendor/github.com/go-ldap/ldap/v3/ldap.go index e2c758fbcc6..90837a7743a 100644 --- a/vendor/github.com/go-ldap/ldap/v3/ldap.go +++ b/vendor/github.com/go-ldap/ldap/v3/ldap.go @@ -32,6 +32,7 @@ const ( ApplicationSearchResultReference = 19 ApplicationExtendedRequest = 23 ApplicationExtendedResponse = 24 + ApplicationIntermediateResponse = 25 ) // ApplicationMap contains human readable descriptions of LDAP Application Codes @@ -56,6 +57,7 @@ var ApplicationMap = map[uint8]string{ ApplicationSearchResultReference: "Search Result Reference", ApplicationExtendedRequest: "Extended Request", ApplicationExtendedResponse: "Extended Response", + ApplicationIntermediateResponse: "Intermediate Response", } // Ldap Behera Password Policy Draft 10 (https://tools.ietf.org/html/draft-behera-ldap-password-policy-10) diff --git a/vendor/github.com/go-ldap/ldap/v3/response.go b/vendor/github.com/go-ldap/ldap/v3/response.go new file mode 100644 index 00000000000..1abe02a37f2 --- /dev/null +++ b/vendor/github.com/go-ldap/ldap/v3/response.go @@ -0,0 +1,207 @@ +package ldap + +import ( + "context" + "errors" + "fmt" + + ber "github.com/go-asn1-ber/asn1-ber" +) + +// Response defines an interface to get data from an LDAP server +type Response interface { + Entry() *Entry + Referral() string + Controls() []Control + Err() error + Next() bool +} + +type searchResponse struct { + conn *Conn + ch chan *SearchSingleResult + + entry *Entry + referral string + controls []Control + err error +} + +// Entry returns an entry from the given search request +func (r *searchResponse) Entry() *Entry { + return r.entry +} + +// Referral returns a referral from the given search request +func (r *searchResponse) Referral() string { + return r.referral +} + +// Controls returns controls from the given search request +func (r *searchResponse) Controls() []Control { + return r.controls +} + +// Err returns an error when the given search request was failed +func (r *searchResponse) Err() error { + return r.err +} + +// Next returns whether next data exist or not +func (r *searchResponse) Next() bool { + res, ok := <-r.ch + if !ok { + return false + } + if res == nil { + return false + } + r.err = res.Error + if r.err != nil { + return false + } + r.entry = res.Entry + r.referral = res.Referral + r.controls = res.Controls + return true +} + +func (r *searchResponse) start(ctx context.Context, searchRequest *SearchRequest) { + go func() { + defer func() { + close(r.ch) + if err := recover(); err != nil { + r.conn.err = fmt.Errorf("ldap: recovered panic in searchResponse: %v", err) + } + }() + + if r.conn.IsClosing() { + return + } + + packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request") + packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, r.conn.nextMessageID(), "MessageID")) + // encode search request + err := searchRequest.appendTo(packet) + if err != nil { + r.ch <- &SearchSingleResult{Error: err} + return + } + r.conn.Debug.PrintPacket(packet) + + msgCtx, err := r.conn.sendMessage(packet) + if err != nil { + r.ch <- &SearchSingleResult{Error: err} + return + } + defer r.conn.finishMessage(msgCtx) + + foundSearchSingleResultDone := false + for !foundSearchSingleResultDone { + select { + case <-ctx.Done(): + r.conn.Debug.Printf("%d: %s", msgCtx.id, ctx.Err().Error()) + return + default: + r.conn.Debug.Printf("%d: waiting for response", msgCtx.id) + packetResponse, ok := <-msgCtx.responses + if !ok { + err := NewError(ErrorNetwork, errors.New("ldap: response channel closed")) + r.ch <- &SearchSingleResult{Error: err} + return + } + packet, err = packetResponse.ReadPacket() + r.conn.Debug.Printf("%d: got response %p", msgCtx.id, packet) + if err != nil { + r.ch <- &SearchSingleResult{Error: err} + return + } + + if r.conn.Debug { + if err := addLDAPDescriptions(packet); err != nil { + r.ch <- &SearchSingleResult{Error: err} + return + } + ber.PrintPacket(packet) + } + + switch packet.Children[1].Tag { + case ApplicationSearchResultEntry: + result := &SearchSingleResult{ + Entry: &Entry{ + DN: packet.Children[1].Children[0].Value.(string), + Attributes: unpackAttributes(packet.Children[1].Children[1].Children), + }, + } + if len(packet.Children) != 3 { + r.ch <- result + continue + } + decoded, err := DecodeControl(packet.Children[2].Children[0]) + if err != nil { + werr := fmt.Errorf("failed to decode search result entry: %w", err) + result.Error = werr + r.ch <- result + return + } + result.Controls = append(result.Controls, decoded) + r.ch <- result + + case ApplicationSearchResultDone: + if err := GetLDAPError(packet); err != nil { + r.ch <- &SearchSingleResult{Error: err} + return + } + if len(packet.Children) == 3 { + result := &SearchSingleResult{} + for _, child := range packet.Children[2].Children { + decodedChild, err := DecodeControl(child) + if err != nil { + werr := fmt.Errorf("failed to decode child control: %w", err) + r.ch <- &SearchSingleResult{Error: werr} + return + } + result.Controls = append(result.Controls, decodedChild) + } + r.ch <- result + } + foundSearchSingleResultDone = true + + case ApplicationSearchResultReference: + ref := packet.Children[1].Children[0].Value.(string) + r.ch <- &SearchSingleResult{Referral: ref} + + case ApplicationIntermediateResponse: + decoded, err := DecodeControl(packet.Children[1]) + if err != nil { + werr := fmt.Errorf("failed to decode intermediate response: %w", err) + r.ch <- &SearchSingleResult{Error: werr} + return + } + result := &SearchSingleResult{} + result.Controls = append(result.Controls, decoded) + r.ch <- result + + default: + err := fmt.Errorf("unknown tag: %d", packet.Children[1].Tag) + r.ch <- &SearchSingleResult{Error: err} + return + } + } + } + r.conn.Debug.Printf("%d: returning", msgCtx.id) + }() +} + +func newSearchResponse(conn *Conn, bufferSize int) *searchResponse { + var ch chan *SearchSingleResult + if bufferSize > 0 { + ch = make(chan *SearchSingleResult, bufferSize) + } else { + ch = make(chan *SearchSingleResult) + } + return &searchResponse{ + conn: conn, + ch: ch, + } +} diff --git a/vendor/github.com/go-ldap/ldap/v3/search.go b/vendor/github.com/go-ldap/ldap/v3/search.go index 9c0ccd07175..4eb10762db4 100644 --- a/vendor/github.com/go-ldap/ldap/v3/search.go +++ b/vendor/github.com/go-ldap/ldap/v3/search.go @@ -1,6 +1,7 @@ package ldap import ( + "context" "errors" "fmt" "reflect" @@ -377,6 +378,28 @@ func (s *SearchResult) appendTo(r *SearchResult) { r.Controls = append(r.Controls, s.Controls...) } +// SearchSingleResult holds the server's single entry response to a search request +type SearchSingleResult struct { + // Entry is the returned entry + Entry *Entry + // Referral is the returned referral + Referral string + // Controls are the returned controls + Controls []Control + // Error is set when the search request was failed + Error error +} + +// Print outputs a human-readable description +func (s *SearchSingleResult) Print() { + s.Entry.Print() +} + +// PrettyPrint outputs a human-readable description with indenting +func (s *SearchSingleResult) PrettyPrint(indent int) { + s.Entry.PrettyPrint(indent) +} + // SearchRequest represents a search request to send to the server type SearchRequest struct { BaseDN string @@ -561,6 +584,32 @@ func (l *Conn) Search(searchRequest *SearchRequest) (*SearchResult, error) { } } +// SearchAsync performs a search request and returns all search results asynchronously. +// This means you get all results until an error happens (or the search successfully finished), +// e.g. for size / time limited requests all are recieved until the limit is reached. +// To stop the search, call cancel function of the context. +func (l *Conn) SearchAsync( + ctx context.Context, searchRequest *SearchRequest, bufferSize int) Response { + r := newSearchResponse(l, bufferSize) + r.start(ctx, searchRequest) + return r +} + +// Syncrepl is a short name for LDAP Sync Replication engine that works on the +// consumer-side. This can perform a persistent search and returns an entry +// when the entry is updated on the server side. +// To stop the search, call cancel function of the context. +func (l *Conn) Syncrepl( + ctx context.Context, searchRequest *SearchRequest, bufferSize int, + mode ControlSyncRequestMode, cookie []byte, reloadHint bool, +) Response { + control := NewControlSyncRequest(mode, cookie, reloadHint) + searchRequest.Controls = append(searchRequest.Controls, control) + r := newSearchResponse(l, bufferSize) + r.start(ctx, searchRequest) + return r +} + // unpackAttributes will extract all given LDAP attributes and it's values // from the ber.Packet func unpackAttributes(children []*ber.Packet) []*EntryAttribute { @@ -586,55 +635,56 @@ func unpackAttributes(children []*ber.Packet) []*EntryAttribute { } // DirSync does a Search with dirSync Control. -func (l *Conn) DirSync(searchRequest *SearchRequest, flags int64, maxAttrCount int64, cookie []byte) (*SearchResult, error) { - var dirSyncControl *ControlDirSync - +func (l *Conn) DirSync( + searchRequest *SearchRequest, flags int64, maxAttrCount int64, cookie []byte, +) (*SearchResult, error) { control := FindControl(searchRequest.Controls, ControlTypeDirSync) if control == nil { - dirSyncControl = NewControlDirSync(flags, maxAttrCount, cookie) - searchRequest.Controls = append(searchRequest.Controls, dirSyncControl) + c := NewRequestControlDirSync(flags, maxAttrCount, cookie) + searchRequest.Controls = append(searchRequest.Controls, c) } else { - castControl, ok := control.(*ControlDirSync) - if !ok { - return nil, fmt.Errorf("Expected DirSync control to be of type *ControlDirSync, got %v", control) - } - if castControl.Flags != flags { - return nil, fmt.Errorf("flags given in search request (%d) conflicts with flags given in search call (%d)", castControl.Flags, flags) + c := control.(*ControlDirSync) + if c.Flags != flags { + return nil, fmt.Errorf("flags given in search request (%d) conflicts with flags given in search call (%d)", c.Flags, flags) } - if castControl.MaxAttrCnt != maxAttrCount { - return nil, fmt.Errorf("MaxAttrCnt given in search request (%d) conflicts with maxAttrCount given in search call (%d)", castControl.MaxAttrCnt, maxAttrCount) + if c.MaxAttrCount != maxAttrCount { + return nil, fmt.Errorf("MaxAttrCnt given in search request (%d) conflicts with maxAttrCount given in search call (%d)", c.MaxAttrCount, maxAttrCount) } - dirSyncControl = castControl } - searchResult := new(SearchResult) - result, err := l.Search(searchRequest) + searchResult, err := l.Search(searchRequest) l.Debug.Printf("Looking for result...") if err != nil { - return searchResult, err + return nil, err } - if result == nil { - return searchResult, NewError(ErrorNetwork, errors.New("ldap: packet not received")) + if searchResult == nil { + return nil, NewError(ErrorNetwork, errors.New("ldap: packet not received")) } - searchResult.Entries = append(searchResult.Entries, result.Entries...) - searchResult.Referrals = append(searchResult.Referrals, result.Referrals...) - searchResult.Controls = append(searchResult.Controls, result.Controls...) - l.Debug.Printf("Looking for DirSync Control...") - dirSyncResult := FindControl(result.Controls, ControlTypeDirSync) - if dirSyncResult == nil { - dirSyncControl = nil + resultControl := FindControl(searchResult.Controls, ControlTypeDirSync) + if resultControl == nil { l.Debug.Printf("Could not find dirSyncControl control. Breaking...") return searchResult, nil } - cookie = dirSyncResult.(*ControlDirSync).Cookie + cookie = resultControl.(*ControlDirSync).Cookie if len(cookie) == 0 { - dirSyncControl = nil l.Debug.Printf("Could not find cookie. Breaking...") return searchResult, nil } - dirSyncControl.SetCookie(cookie) return searchResult, nil } + +// DirSyncDirSyncAsync performs a search request and returns all search results +// asynchronously. This is efficient when the server returns lots of entries. +func (l *Conn) DirSyncAsync( + ctx context.Context, searchRequest *SearchRequest, bufferSize int, + flags, maxAttrCount int64, cookie []byte, +) Response { + control := NewRequestControlDirSync(flags, maxAttrCount, cookie) + searchRequest.Controls = append(searchRequest.Controls, control) + r := newSearchResponse(l, bufferSize) + r.start(ctx, searchRequest) + return r +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 929db9e898e..bfb9769995b 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -789,7 +789,7 @@ github.com/ghodss/yaml ## explicit; go 1.15 github.com/go-acme/lego/v4/acme github.com/go-acme/lego/v4/challenge -# github.com/go-asn1-ber/asn1-ber v1.5.4 +# github.com/go-asn1-ber/asn1-ber v1.5.5 ## explicit; go 1.13 github.com/go-asn1-ber/asn1-ber # github.com/go-chi/chi/v5 v5.0.10 @@ -869,7 +869,7 @@ github.com/go-jose/go-jose/v3/json ## explicit; go 1.17 github.com/go-kit/log github.com/go-kit/log/level -# github.com/go-ldap/ldap/v3 v3.4.5 +# github.com/go-ldap/ldap/v3 v3.4.6 ## explicit; go 1.14 github.com/go-ldap/ldap/v3 # github.com/go-ldap/ldif v0.0.0-20200320164324-fd88d9b715b3