61 lines
1.7 KiB
Go
61 lines
1.7 KiB
Go
// +build windows
|
|
|
|
package sshprovider
|
|
|
|
import (
|
|
"net"
|
|
"regexp"
|
|
"strings"
|
|
|
|
"github.com/Microsoft/go-winio"
|
|
"github.com/pkg/errors"
|
|
"golang.org/x/sys/windows"
|
|
)
|
|
|
|
// Returns the Windows OpenSSH agent named pipe path, but
|
|
// only if the agent is running. Returns an error otherwise.
|
|
func getFallbackAgentPath() (string, error) {
|
|
// Windows OpenSSH agent uses a named pipe rather
|
|
// than a UNIX socket. These pipes do not play nice
|
|
// with os.Stat (which tries to open its target), so
|
|
// use a FindFirstFile syscall to check for existence.
|
|
var fd windows.Win32finddata
|
|
|
|
path := `\\.\pipe\openssh-ssh-agent`
|
|
pathPtr, _ := windows.UTF16PtrFromString(path)
|
|
handle, err := windows.FindFirstFile(pathPtr, &fd)
|
|
|
|
if err != nil {
|
|
msg := "Windows OpenSSH agent not available at %s." +
|
|
" Enable the SSH agent service or set SSH_AUTH_SOCK."
|
|
return "", errors.Errorf(msg, path)
|
|
}
|
|
|
|
_ = windows.CloseHandle(handle)
|
|
|
|
return path, nil
|
|
}
|
|
|
|
// Returns true if the path references a named pipe.
|
|
func isWindowsPipePath(path string) bool {
|
|
// If path matches \\*\pipe\* then it references a named pipe
|
|
// and requires winio.DialPipe() rather than DialTimeout("unix").
|
|
// Slashes and backslashes may be used interchangeably in the path.
|
|
// Path separators may consist of multiple consecutive (back)slashes.
|
|
pipePattern := strings.ReplaceAll("^[/]{2}[^/]+[/]+pipe[/]+", "/", `\\/`)
|
|
ok, _ := regexp.MatchString(pipePattern, path)
|
|
return ok
|
|
}
|
|
|
|
func getWindowsPipeDialer(path string) *socketDialer {
|
|
if isWindowsPipePath(path) {
|
|
return &socketDialer{path: path, dialer: windowsPipeDialer}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func windowsPipeDialer(path string) (net.Conn, error) {
|
|
return winio.DialPipe(path, nil)
|
|
}
|