From d4d810d4a6b440a32b5d35a7183fa39d092d5337 Mon Sep 17 00:00:00 2001 From: Ilya Basin Date: Fri, 8 Mar 2019 16:56:43 +0300 Subject: [PATCH] Windows ssh-agent workaround --- lib/sshcryptagent/agent.go | 65 ++++++++++++++++++++++++++-- lib/sshcryptagent/cmdline_generic.go | 15 +++++++ lib/sshcryptagent/cmdline_windows.go | 15 +++++++ 3 files changed, 92 insertions(+), 3 deletions(-) create mode 100644 lib/sshcryptagent/cmdline_generic.go create mode 100644 lib/sshcryptagent/cmdline_windows.go diff --git a/lib/sshcryptagent/agent.go b/lib/sshcryptagent/agent.go index 9e6f527..f9fb6f1 100644 --- a/lib/sshcryptagent/agent.go +++ b/lib/sshcryptagent/agent.go @@ -2,17 +2,48 @@ package sshcryptagent import ( "fmt" + "io" "net" "os" + "strings" "golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh/agent" ) +type ReadWriter struct { + io.Reader + io.Writer +} + +func NewReadWriter(r io.Reader, w io.Writer) io.ReadWriter { + return &ReadWriter{r, w} +} + func GetSigners() ([]ssh.Signer, error) { - conn, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK")) - if err != nil { - return nil, fmt.Errorf("Could not connect to the SSH Agent socket. %s", err) + sockAddr := os.Getenv("SSH_AUTH_SOCK") + + // ex: "socat.exe - UNIX-CONNECT:%a" + socatFormat := os.Getenv("SSH_AUTH_SOCAT") + var conn io.ReadWriter + var err error + if len(socatFormat) > 0 { + socatCommand := fmtCommand(socatFormat, sockAddr) + cmd := MkCommand(socatCommand) + cmd.Stderr = os.Stderr + pipeRd, err := cmd.StdoutPipe() + pipeWr, err := cmd.StdinPipe() + + err = cmd.Start() + if err != nil { + return nil, fmt.Errorf("Could not start \"%s\": %s", socatCommand, err) + } + conn = NewReadWriter(pipeRd, pipeWr) + } else { + conn, err = net.Dial("unix", sockAddr) + if err != nil { + return nil, fmt.Errorf("Could not connect to the SSH Agent socket. %s", err) + } } sshAgent := agent.NewClient(conn) @@ -27,3 +58,31 @@ func GetSigners() ([]ssh.Signer, error) { return signers, nil } + +func fmtCommand(format string, address string) string { + var out strings.Builder + inPercent := false + for _, c := range format { + if inPercent { + inPercent = false + if (c == '%') { + out.WriteRune('%'); + } else if (c == 'a') { + out.WriteString(address); + } else { + out.WriteRune('%') + out.WriteRune(c); + } + } else { + if c == '%' { + inPercent = true + } else { + out.WriteRune(c); + } + } + } + if inPercent { + out.WriteRune('%') + } + return out.String() +} diff --git a/lib/sshcryptagent/cmdline_generic.go b/lib/sshcryptagent/cmdline_generic.go new file mode 100644 index 0000000..6d406c7 --- /dev/null +++ b/lib/sshcryptagent/cmdline_generic.go @@ -0,0 +1,15 @@ +// +build !windows,!plan9 + +package sshcryptagent + + +import ( + "os/exec" +) + + +// + +func MkCommand(cmdline string) *exec.Cmd { + return exec.Command("sh", "-c", cmdline); +} \ No newline at end of file diff --git a/lib/sshcryptagent/cmdline_windows.go b/lib/sshcryptagent/cmdline_windows.go new file mode 100644 index 0000000..1672b66 --- /dev/null +++ b/lib/sshcryptagent/cmdline_windows.go @@ -0,0 +1,15 @@ +// +build windows + +package sshcryptagent + + +import ( + "os/exec" +) + + +// + +func MkCommand(cmdline string) *exec.Cmd { + return exec.Command("cmd.exe", "/c", cmdline); +} \ No newline at end of file