main
Raw Download raw file
  1//
  2// Copyright (c) 2014 David Mzareulyan
  3//
  4// Permission is hereby granted, free of charge, to any person obtaining a copy of this software
  5// and associated documentation files (the "Software"), to deal in the Software without restriction,
  6// including without limitation the rights to use, copy, modify, merge, publish, distribute,
  7// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
  8// is furnished to do so, subject to the following conditions:
  9//
 10// The above copyright notice and this permission notice shall be included in all copies or substantial
 11// portions of the Software.
 12//
 13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
 14// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 15// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 16// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 17// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 18//
 19
 20//go:build windows
 21// +build windows
 22
 23package sshagent
 24
 25import (
 26	"errors"
 27	"io"
 28	"net"
 29	"sync"
 30
 31	"github.com/Microsoft/go-winio"
 32	"golang.org/x/crypto/ssh/agent"
 33)
 34
 35const (
 36	sshAgentPipe = `\\.\pipe\openssh-ssh-agent`
 37)
 38
 39// Available returns true if Pageant is running
 40func Available() bool {
 41	if pageantWindow() != 0 {
 42		return true
 43	}
 44	conn, err := winio.DialPipe(sshAgentPipe, nil)
 45	if err != nil {
 46		return false
 47	}
 48	conn.Close()
 49	return true
 50}
 51
 52// New returns a new agent.Agent and the (custom) connection it uses
 53// to communicate with a running pagent.exe instance (see README.md)
 54func New() (agent.Agent, net.Conn, error) {
 55	if pageantWindow() != 0 {
 56		return agent.NewClient(&conn{}), nil, nil
 57	}
 58	conn, err := winio.DialPipe(sshAgentPipe, nil)
 59	if err != nil {
 60		return nil, nil, errors.New(
 61			"SSH agent requested, but could not detect Pageant or Windows native SSH agent",
 62		)
 63	}
 64	return agent.NewClient(conn), nil, nil
 65}
 66
 67type conn struct {
 68	sync.Mutex
 69	buf []byte
 70}
 71
 72func (c *conn) Close() {
 73	c.Lock()
 74	defer c.Unlock()
 75	c.buf = nil
 76}
 77
 78func (c *conn) Write(p []byte) (int, error) {
 79	c.Lock()
 80	defer c.Unlock()
 81
 82	resp, err := query(p)
 83	if err != nil {
 84		return 0, err
 85	}
 86
 87	c.buf = append(c.buf, resp...)
 88
 89	return len(p), nil
 90}
 91
 92func (c *conn) Read(p []byte) (int, error) {
 93	c.Lock()
 94	defer c.Unlock()
 95
 96	if len(c.buf) == 0 {
 97		return 0, io.EOF
 98	}
 99
100	n := copy(p, c.buf)
101	c.buf = c.buf[n:]
102
103	return n, nil
104}