-
Notifications
You must be signed in to change notification settings - Fork 1
/
conn.go
121 lines (108 loc) · 3.14 KB
/
conn.go
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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package ldapserver
import (
"bytes"
"crypto/tls"
"io"
"net"
"sync"
)
type Encodable interface {
Encode() []byte
}
type Conn struct {
// Underlying network connection
conn net.Conn
// Flag to signal server to stop reading messages
closed bool
// Whether the underlying connection has TLS set up
isTLS bool
// TLS config for StartTLS connections
TLSConfig *tls.Config
// Mutex to prevent reading/writing while setting up TLS
tlsStarting sync.RWMutex
// Mutex to synchronize message sending
sending sync.Mutex
// Wait group to enable atomic Bind request processing
asyncOperations sync.WaitGroup
// User-defined authentication storage
Authentication any
// User-defined message storage to enable Abandon functionality.
// The Conn does not touch the cache.
MessageCache map[MessageID]any
}
// Returns the local address of the connection
func (c *Conn) LocalAddr() net.Addr {
return c.conn.LocalAddr()
}
// Returns the remote address of the connection
func (c *Conn) RemoteAddr() net.Addr {
return c.conn.RemoteAddr()
}
// Returns whether the underlying connection has TLS set up
func (c *Conn) IsTLS() bool {
return c.isTLS
}
// Closes the underlying connection and stops reading messages.
func (c *Conn) Close() {
c.conn.Close()
c.closed = true
}
// Sends a notice of disconnection to the client
func (c *Conn) NotifyDisconnect(resultCode LDAPResultCode, diagnosticMessage string) error {
return c.SendUnsolicitedNotification(resultCode, diagnosticMessage, OIDNoticeOfDisconnection, "")
}
// Reads a LDAPMessage from the connection
func (c *Conn) ReadMessage() (*Message, error) {
return ReadLDAPMessage(c.conn)
}
// Sends an Extended Result with a message ID of 0
func (c *Conn) SendUnsolicitedNotification(resultCode LDAPResultCode, diagnosticMessage string, oid OID, respValue string) error {
res := ExtendedResult{
Result: Result{
ResultCode: resultCode,
DiagnosticMessage: diagnosticMessage,
},
ResponseName: oid,
ResponseValue: respValue,
}
return c.SendResult(0, nil, TypeExtendedResponseOp, &res)
}
// Sends a LDAPMessage to the client and removes the corresponding message from the abandonment cache
func (c *Conn) SendMessage(msg *Message) error {
c.tlsStarting.RLock()
defer c.tlsStarting.RUnlock()
c.sending.Lock()
defer c.sending.Unlock()
_, err := io.Copy(c.conn, bytes.NewReader(msg.EncodeWithHeader()))
return err
}
// Starts TLS on the underlying connection if not already started
func (c *Conn) StartTLS() error {
c.tlsStarting.Lock()
defer c.tlsStarting.Unlock()
if c.isTLS {
return ErrTLSAlreadySetUp
}
if c.TLSConfig == nil {
return ErrTLSNotAvailable
}
tlsConn := tls.Server(c.conn, c.TLSConfig)
err := tlsConn.Handshake()
if err != nil {
return err
}
c.conn = tlsConn
c.isTLS = true
return nil
}
// Sends a LDAPResult to the client with specified parameters.
// Pass an object with an Encode() function returning []byte to res.
func (c *Conn) SendResult(messageID MessageID, controls []Control, rtype BerType, res Encodable) error {
msg := Message{
MessageID: messageID,
Controls: controls,
}
msg.ProtocolOp.Type = rtype
msg.ProtocolOp.Data = res.Encode()
return c.SendMessage(&msg)
}