...
1 package ldap
2
3 import (
4 "context"
5 "errors"
6 "fmt"
7
8 ber "github.com/go-asn1-ber/asn1-ber"
9 )
10
11
12 type Response interface {
13 Entry() *Entry
14 Referral() string
15 Controls() []Control
16 Err() error
17 Next() bool
18 }
19
20 type searchResponse struct {
21 conn *Conn
22 ch chan *SearchSingleResult
23
24 entry *Entry
25 referral string
26 controls []Control
27 err error
28 }
29
30
31 func (r *searchResponse) Entry() *Entry {
32 return r.entry
33 }
34
35
36 func (r *searchResponse) Referral() string {
37 return r.referral
38 }
39
40
41 func (r *searchResponse) Controls() []Control {
42 return r.controls
43 }
44
45
46 func (r *searchResponse) Err() error {
47 return r.err
48 }
49
50
51 func (r *searchResponse) Next() bool {
52 res, ok := <-r.ch
53 if !ok {
54 return false
55 }
56 if res == nil {
57 return false
58 }
59 r.err = res.Error
60 if r.err != nil {
61 return false
62 }
63 r.entry = res.Entry
64 r.referral = res.Referral
65 r.controls = res.Controls
66 return true
67 }
68
69 func (r *searchResponse) start(ctx context.Context, searchRequest *SearchRequest) {
70 go func() {
71 defer func() {
72 close(r.ch)
73 if err := recover(); err != nil {
74 r.conn.err = fmt.Errorf("ldap: recovered panic in searchResponse: %v", err)
75 }
76 }()
77
78 if r.conn.IsClosing() {
79 return
80 }
81
82 packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
83 packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, r.conn.nextMessageID(), "MessageID"))
84
85 err := searchRequest.appendTo(packet)
86 if err != nil {
87 r.ch <- &SearchSingleResult{Error: err}
88 return
89 }
90 r.conn.Debug.PrintPacket(packet)
91
92 msgCtx, err := r.conn.sendMessage(packet)
93 if err != nil {
94 r.ch <- &SearchSingleResult{Error: err}
95 return
96 }
97 defer r.conn.finishMessage(msgCtx)
98
99 foundSearchSingleResultDone := false
100 for !foundSearchSingleResultDone {
101 select {
102 case <-ctx.Done():
103 r.conn.Debug.Printf("%d: %s", msgCtx.id, ctx.Err().Error())
104 return
105 default:
106 r.conn.Debug.Printf("%d: waiting for response", msgCtx.id)
107 packetResponse, ok := <-msgCtx.responses
108 if !ok {
109 err := NewError(ErrorNetwork, errors.New("ldap: response channel closed"))
110 r.ch <- &SearchSingleResult{Error: err}
111 return
112 }
113 packet, err = packetResponse.ReadPacket()
114 r.conn.Debug.Printf("%d: got response %p", msgCtx.id, packet)
115 if err != nil {
116 r.ch <- &SearchSingleResult{Error: err}
117 return
118 }
119
120 if r.conn.Debug {
121 if err := addLDAPDescriptions(packet); err != nil {
122 r.ch <- &SearchSingleResult{Error: err}
123 return
124 }
125 ber.PrintPacket(packet)
126 }
127
128 switch packet.Children[1].Tag {
129 case ApplicationSearchResultEntry:
130 result := &SearchSingleResult{
131 Entry: &Entry{
132 DN: packet.Children[1].Children[0].Value.(string),
133 Attributes: unpackAttributes(packet.Children[1].Children[1].Children),
134 },
135 }
136 if len(packet.Children) != 3 {
137 r.ch <- result
138 continue
139 }
140 decoded, err := DecodeControl(packet.Children[2].Children[0])
141 if err != nil {
142 werr := fmt.Errorf("failed to decode search result entry: %w", err)
143 result.Error = werr
144 r.ch <- result
145 return
146 }
147 result.Controls = append(result.Controls, decoded)
148 r.ch <- result
149
150 case ApplicationSearchResultDone:
151 if err := GetLDAPError(packet); err != nil {
152 r.ch <- &SearchSingleResult{Error: err}
153 return
154 }
155 if len(packet.Children) == 3 {
156 result := &SearchSingleResult{}
157 for _, child := range packet.Children[2].Children {
158 decodedChild, err := DecodeControl(child)
159 if err != nil {
160 werr := fmt.Errorf("failed to decode child control: %w", err)
161 r.ch <- &SearchSingleResult{Error: werr}
162 return
163 }
164 result.Controls = append(result.Controls, decodedChild)
165 }
166 r.ch <- result
167 }
168 foundSearchSingleResultDone = true
169
170 case ApplicationSearchResultReference:
171 ref := packet.Children[1].Children[0].Value.(string)
172 r.ch <- &SearchSingleResult{Referral: ref}
173
174 case ApplicationIntermediateResponse:
175 decoded, err := DecodeControl(packet.Children[1])
176 if err != nil {
177 werr := fmt.Errorf("failed to decode intermediate response: %w", err)
178 r.ch <- &SearchSingleResult{Error: werr}
179 return
180 }
181 result := &SearchSingleResult{}
182 result.Controls = append(result.Controls, decoded)
183 r.ch <- result
184
185 default:
186 err := fmt.Errorf("unknown tag: %d", packet.Children[1].Tag)
187 r.ch <- &SearchSingleResult{Error: err}
188 return
189 }
190 }
191 }
192 r.conn.Debug.Printf("%d: returning", msgCtx.id)
193 }()
194 }
195
196 func newSearchResponse(conn *Conn, bufferSize int) *searchResponse {
197 var ch chan *SearchSingleResult
198 if bufferSize > 0 {
199 ch = make(chan *SearchSingleResult, bufferSize)
200 } else {
201 ch = make(chan *SearchSingleResult)
202 }
203 return &searchResponse{
204 conn: conn,
205 ch: ch,
206 }
207 }
208
View as plain text