47df570d18
These updates make it easier to implement and pass custom Session and Context implementations No compatibilty breaking, all tests pass
84 lines
2.0 KiB
Go
84 lines
2.0 KiB
Go
package ssh
|
|
|
|
import (
|
|
"io"
|
|
"io/ioutil"
|
|
"net"
|
|
"path"
|
|
"sync"
|
|
|
|
gossh "golang.org/x/crypto/ssh"
|
|
)
|
|
|
|
const (
|
|
agentRequestType = "auth-agent-req@openssh.com"
|
|
agentChannelType = "auth-agent@openssh.com"
|
|
|
|
agentTempDir = "auth-agent"
|
|
agentListenFile = "listener.sock"
|
|
)
|
|
|
|
// contextKeyAgentRequest is an internal context key for storing if the
|
|
// client requested agent forwarding
|
|
var contextKeyAgentRequest = &contextKey{"auth-agent-req"}
|
|
|
|
// SetAgentRequested sets up the session context so that AgentRequested
|
|
// returns true.
|
|
func SetAgentRequested(ctx Context) {
|
|
ctx.SetValue(contextKeyAgentRequest, true)
|
|
}
|
|
|
|
// AgentRequested returns true if the client requested agent forwarding.
|
|
func AgentRequested(sess Session) bool {
|
|
return sess.Context().Value(contextKeyAgentRequest) == true
|
|
}
|
|
|
|
// NewAgentListener sets up a temporary Unix socket that can be communicated
|
|
// to the session environment and used for forwarding connections.
|
|
func NewAgentListener() (net.Listener, error) {
|
|
dir, err := ioutil.TempDir("", agentTempDir)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
l, err := net.Listen("unix", path.Join(dir, agentListenFile))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return l, nil
|
|
}
|
|
|
|
// ForwardAgentConnections takes connections from a listener to proxy into the
|
|
// session on the OpenSSH channel for agent connections. It blocks and services
|
|
// connections until the listener stop accepting.
|
|
func ForwardAgentConnections(l net.Listener, s Session) {
|
|
sshConn := s.Context().Value(ContextKeyConn).(gossh.Conn)
|
|
for {
|
|
conn, err := l.Accept()
|
|
if err != nil {
|
|
return
|
|
}
|
|
go func(conn net.Conn) {
|
|
defer conn.Close()
|
|
channel, reqs, err := sshConn.OpenChannel(agentChannelType, nil)
|
|
if err != nil {
|
|
return
|
|
}
|
|
defer channel.Close()
|
|
go gossh.DiscardRequests(reqs)
|
|
var wg sync.WaitGroup
|
|
wg.Add(2)
|
|
go func() {
|
|
io.Copy(conn, channel)
|
|
conn.(*net.UnixConn).CloseWrite()
|
|
wg.Done()
|
|
}()
|
|
go func() {
|
|
io.Copy(channel, conn)
|
|
channel.CloseWrite()
|
|
wg.Done()
|
|
}()
|
|
wg.Wait()
|
|
}(conn)
|
|
}
|
|
}
|