-
Notifications
You must be signed in to change notification settings - Fork 102
Expand file tree
/
Copy pathcancel.go
More file actions
82 lines (71 loc) · 2.26 KB
/
cancel.go
File metadata and controls
82 lines (71 loc) · 2.26 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
package ldapserver
import (
"encoding/asn1"
"fmt"
ldap "github.com/vjeantet/goldap/message"
)
// cancelRequestValue represents the ASN.1 value of a Cancel Extended Request
// per RFC 3909: cancelRequestValue ::= SEQUENCE { cancelID MessageID }
type cancelRequestValue struct {
CancelID int
}
// parseCancelRequestValue decodes the cancelID from the BER-encoded
// requestValue of a Cancel Extended Request (OID 1.3.6.1.1.8).
func parseCancelRequestValue(raw *ldap.OCTETSTRING) (int, error) {
if raw == nil {
return 0, fmt.Errorf("cancel request: missing requestValue")
}
var val cancelRequestValue
rest, err := asn1.Unmarshal([]byte(*raw), &val)
if err != nil {
return 0, fmt.Errorf("cancel request: failed to decode requestValue: %w", err)
}
if len(rest) > 0 {
return 0, fmt.Errorf("cancel request: trailing data after requestValue")
}
if val.CancelID < 1 {
return 0, fmt.Errorf("cancel request: invalid cancelID %d", val.CancelID)
}
return val.CancelID, nil
}
// handleCancel is the built-in handler for the Cancel Extended Operation
// (RFC 3909, OID 1.3.6.1.1.8). It signals the target operation to abort
// and responds with an ExtendedResponse.
func handleCancel(w ResponseWriter, r *Message) {
req := r.GetExtendedRequest()
cancelID, err := parseCancelRequestValue(req.RequestValue())
if err != nil {
res := NewExtendedResponse(LDAPResultProtocolError)
res.SetDiagnosticMessage(err.Error())
w.Write(res)
return
}
// Look up the target message
target, ok := r.Client.GetMessageByID(cancelID)
if !ok {
res := NewExtendedResponse(LDAPResultNoSuchOperation)
w.Write(res)
return
}
// Check for non-cancelable operations per RFC 3909 section 2.
// Unbind is not checked because it causes immediate disconnect
// and is never in requestList.
switch target.ProtocolOp().(type) {
case ldap.BindRequest, ldap.AbandonRequest:
res := NewExtendedResponse(LDAPResultCannotCancel)
w.Write(res)
return
case ldap.ExtendedRequest:
ext := target.GetExtendedRequest()
name := ext.RequestName()
if name == NoticeOfStartTLS || name == NoticeOfCancel {
res := NewExtendedResponse(LDAPResultCannotCancel)
w.Write(res)
return
}
}
// Signal the target to abort
target.Abandon()
res := NewExtendedResponse(LDAPResultCanceled)
w.Write(res)
}