/
client.go
158 lines (144 loc) · 3.16 KB
/
client.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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package namedpipe
import (
"fmt"
"io"
"sync"
"github.com/Microsoft/go-winio"
"golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/agent"
)
const (
pipePath = `\\.\pipe\openssh-ssh-agent`
)
type NamedPipeClient struct {
Debug bool
conn io.ReadWriteCloser
mu sync.Mutex
}
func (a *NamedPipeClient) dial() (agent.ExtendedAgent, error) {
if a.conn == nil {
var err error
a.conn, err = winio.DialPipe(pipePath, nil)
if err != nil {
a.conn = nil
return nil, fmt.Errorf("Failed open named-pipe %s, err:%w", pipePath, err)
}
}
return agent.NewClient(a.conn), nil
}
func (a *NamedPipeClient) Close() error {
if a.conn != nil {
err := a.conn.Close()
a.conn = nil
return err
}
return nil
}
func (a *NamedPipeClient) List() ([]*agent.Key, error) {
a.mu.Lock()
defer a.mu.Unlock()
ea, err := a.dial()
if err != nil {
return nil, err
}
defer a.Close()
return ea.List()
}
// Sign has the agent sign the data using a protocol 2 key as defined
// in [PROTOCOL.agent] section 2.6.2.
func (a *NamedPipeClient) Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error) {
a.mu.Lock()
defer a.mu.Unlock()
ea, err := a.dial()
if err != nil {
return nil, err
}
defer a.Close()
return ea.Sign(key, data)
}
// Add adds a private key to the agent.
func (a *NamedPipeClient) Add(key agent.AddedKey) error {
a.mu.Lock()
defer a.mu.Unlock()
ea, err := a.dial()
if err != nil {
return err
}
defer a.Close()
return ea.Add(key)
}
// Remove removes all identities with the given public key.
func (a *NamedPipeClient) Remove(key ssh.PublicKey) error {
a.mu.Lock()
defer a.mu.Unlock()
ea, err := a.dial()
if err != nil {
return err
}
defer a.Close()
return ea.Remove(key)
}
// RemoveAll removes all identities.
func (a *NamedPipeClient) RemoveAll() error {
a.mu.Lock()
defer a.mu.Unlock()
ea, err := a.dial()
if err != nil {
return err
}
defer a.Close()
return ea.RemoveAll()
}
// Lock locks the agent. Sign and Remove will fail, and List will empty an empty list.
func (a *NamedPipeClient) Lock(passphrase []byte) error {
a.mu.Lock()
defer a.mu.Unlock()
ea, err := a.dial()
if err != nil {
return err
}
defer a.Close()
return ea.Lock(passphrase)
}
// Unlock undoes the effect of Lock
func (a *NamedPipeClient) Unlock(passphrase []byte) error {
a.mu.Lock()
defer a.mu.Unlock()
ea, err := a.dial()
if err != nil {
return err
}
defer a.Close()
return ea.Unlock(passphrase)
}
// Signers returns signers for all the known keys.
func (a *NamedPipeClient) Signers() ([]ssh.Signer, error) {
a.mu.Lock()
defer a.mu.Unlock()
ea, err := a.dial()
if err != nil {
return nil, err
}
defer a.Close()
return ea.Signers()
}
func (a *NamedPipeClient) SignWithFlags(key ssh.PublicKey, data []byte, flags agent.SignatureFlags) (*ssh.Signature, error) {
a.mu.Lock()
defer a.mu.Unlock()
ea, err := a.dial()
if err != nil {
return nil, err
}
defer a.Close()
return ea.SignWithFlags(key, data, flags)
}
func (a *NamedPipeClient) Extension(extensionType string, contents []byte) ([]byte, error) {
a.mu.Lock()
defer a.mu.Unlock()
ea, err := a.dial()
if err != nil {
return nil, err
}
defer a.Close()
return ea.Extension(extensionType, contents)
}