func TestAgentForward(t *testing.T) { server := newServer(t) defer server.Shutdown() conn := server.Dial(clientConfig()) defer conn.Close() keyring := agent.NewKeyring() keyring.Add(testPrivateKeys["dsa"], nil, "") pub := testPublicKeys["dsa"] sess, err := conn.NewSession() if err != nil { t.Fatalf("NewSession: %v", err) } if err := agent.RequestAgentForwarding(sess); err != nil { t.Fatalf("RequestAgentForwarding: %v", err) } if err := agent.ForwardToAgent(conn, keyring); err != nil { t.Fatalf("SetupForwardKeyring: %v", err) } out, err := sess.CombinedOutput("ssh-add -L") if err != nil { t.Fatalf("running ssh-add: %v, out %s", err, out) } key, _, _, _, err := ssh.ParseAuthorizedKey(out) if err != nil { t.Fatalf("ParseAuthorizedKey(%q): %v", out, err) } if !bytes.Equal(key.Marshal(), pub.Marshal()) { t.Fatalf("got key %s, want %s", ssh.MarshalAuthorizedKey(key), ssh.MarshalAuthorizedKey(pub)) } }
// Dial creates a client connection to the given SSH server. // // `addr` should be provided in the following format: // // user@host:port // // if `forwardAgent` is true then forwarding of the authentication agent connection will be enabled. func Dial(addr string, socket string, forwardAgent bool) (*SSHConn, error) { agentConn, err := net.Dial("unix", socket) if err != nil { return nil, err } var agentOk bool defer func() { if !agentOk { agentConn.Close() } }() sshAgent := agent.NewClient(agentConn) signers, err := sshAgent.Signers() if err != nil { return nil, err } host, port, user, err := ParseAddr(addr) if err != nil { return nil, err } config := &ssh.ClientConfig{ User: user, Auth: []ssh.AuthMethod{ssh.PublicKeys(signers...)}, Timeout: ConnTimeout, } client, err := ssh.Dial("tcp", fmt.Sprintf("%s:%d", host, port), config) if err != nil { return nil, err } var clientOk bool defer func() { if !clientOk { client.Close() } }() if forwardAgent { if err := agent.ForwardToAgent(client, sshAgent); err != nil { return nil, fmt.Errorf("SetupForwardKeyring: %v", err) } } agentOk = true clientOk = true c := SSHConn{ client: client, agentConn: agentConn, forwardAgent: forwardAgent, } return &c, nil }
func (c *comm) connectToAgent() { if c.client == nil { return } if c.config.DisableAgent { log.Printf("[INFO] SSH agent forwarding is disabled.") return } // open connection to the local agent socketLocation := os.Getenv("SSH_AUTH_SOCK") if socketLocation == "" { log.Printf("[INFO] no local agent socket, will not connect agent") return } agentConn, err := net.Dial("unix", socketLocation) if err != nil { log.Printf("[ERROR] could not connect to local agent socket: %s", socketLocation) return } // create agent and add in auth forwardingAgent := agent.NewClient(agentConn) if forwardingAgent == nil { log.Printf("[ERROR] Could not create agent client") agentConn.Close() return } // add callback for forwarding agent to SSH config // XXX - might want to handle reconnects appending multiple callbacks auth := ssh.PublicKeysCallback(forwardingAgent.Signers) c.config.SSHConfig.Auth = append(c.config.SSHConfig.Auth, auth) agent.ForwardToAgent(c.client, forwardingAgent) // Setup a session to request agent forwarding session, err := c.newSession() if err != nil { return } defer session.Close() err = agent.RequestAgentForwarding(session) if err != nil { log.Printf("[ERROR] RequestAgentForwarding: %#v", err) return } log.Printf("[INFO] agent forwarding enabled") return }
func newSSHForwardingClient(client *gossh.Client, agentForwarding bool) (*SSHForwardingClient, error) { a, err := SSHAgentClient() if err != nil { return nil, err } err = gosshagent.ForwardToAgent(client, a) if err != nil { return nil, err } return &SSHForwardingClient{agentForwarding, client}, nil }
func (c *comm) connectToAgent() { if c.client == nil { return } if c.config.DisableAgent { return } // open connection to the local agent socketLocation := os.Getenv("SSH_AUTH_SOCK") if socketLocation == "" { return } agentConn, err := net.Dial("unix", socketLocation) if err != nil { c.config.Logger.Error("could not connect to local agent socket", "socket_path", socketLocation) return } defer agentConn.Close() // create agent and add in auth forwardingAgent := agent.NewClient(agentConn) if forwardingAgent == nil { c.config.Logger.Error("could not create agent client") return } // add callback for forwarding agent to SSH config // XXX - might want to handle reconnects appending multiple callbacks auth := ssh.PublicKeysCallback(forwardingAgent.Signers) c.config.SSHConfig.Auth = append(c.config.SSHConfig.Auth, auth) agent.ForwardToAgent(c.client, forwardingAgent) // Setup a session to request agent forwarding session, err := c.NewSession() if err != nil { return } defer session.Close() err = agent.RequestAgentForwarding(session) if err != nil { c.config.Logger.Error("error requesting agent forwarding", "error", err) return } return }
func (s *sshClientConfig) NewSession(host string) (*sshSession, error) { conn, err := ssh.Dial("tcp", host, s.ClientConfig) if err != nil { return nil, err } if s.agent != nil { if err := agent.ForwardToAgent(conn, s.agent); err != nil { return nil, err } } session, err := conn.NewSession() if s.agent != nil { err = agent.RequestAgentForwarding(session) } return &sshSession{ conn: conn, Session: session, }, err }
// NewSession creates a new ssh session with the host. // It forwards authentication to the agent when it's configured. func (c *ClientConfig) NewSession(host string) (*Session, error) { conn, err := ssh.Dial("tcp", host, c.ClientConfig) if err != nil { return nil, err } if c.a != nil && c.ForwardAgent { if err := agent.ForwardToAgent(conn, c.a); err != nil { return nil, err } } session, err := conn.NewSession() // Move this up if c.a != nil && c.ForwardAgent { err = agent.RequestAgentForwarding(session) } return &Session{ conn: conn, Session: session, }, err }
func (a *sshAgent) ForwardToAgent(client *ssh.Client) error { return agent.ForwardToAgent(client, a.agent) }
// Exec runs command on remote server. // It is a low-layer method to be used Run, Script and others method. func (c *Communicator) Exec(cmd string, opt *Option, L *lua.LState) (*Result, error) { // get a client client, err := c.Client() if err != nil { return nil, err } // get a session sess, err := client.NewSession() if err != nil { return nil, err } defer sess.Close() // RequestAgentForwarding if c.Config.ForwardAgent && c.Agent != nil { agent.ForwardToAgent(client, c.Agent) if err = agent.RequestAgentForwarding(sess); err != nil { return nil, err } } // Request a PTY if c.Config.Pty { // refers to https://github.com/markpeek/packer/blob/53446bf713ed2866b451aa1d00813a90308ee9e9/communicator/ssh/communicator.go termModes := ssh.TerminalModes{ ssh.ECHO: 0, // do not echo ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud } err = sess.RequestPty("xterm", 80, 40, termModes) if err != nil { return nil, err } } // Compose sudo command line. if opt.Sudo { if opt.User != "" { cmd = "sudo -Sku " + opt.User + " /bin/sh -l -c '" + cmd + "'" } else { cmd = "sudo -Sk /bin/sh -l -c '" + cmd + "'" } } // apply io var outWriter io.Writer var errWriter io.Writer var inReader io.Reader // buffer var outBuffer = new(bytes.Buffer) var errBuffer = new(bytes.Buffer) var inBuffer = new(bytes.Buffer) // append stdio to buffer if opt.UseStdout { if opt.OutputFunc != nil { outWriter = io.MultiWriter(os.Stdout, outBuffer, NewLFuncWriter(1, opt.OutputFunc, L)) } else { outWriter = io.MultiWriter(os.Stdout, outBuffer) } } else { outWriter = io.MultiWriter(outBuffer) } if opt.UseStderr { if opt.OutputFunc != nil { errWriter = io.MultiWriter(os.Stderr, errBuffer, NewLFuncWriter(2, opt.OutputFunc, L)) } else { errWriter = io.MultiWriter(os.Stderr, errBuffer) } } else { errWriter = io.MultiWriter(errBuffer) } inReader = io.MultiReader(inBuffer, os.Stdin) sess.Stdin = inReader sess.Stdout = outWriter sess.Stderr = errWriter // write sudo password if opt.Password != "" { // If it try to use sudo password, write password to input buffer fmt.Fprintln(inBuffer, opt.Password) } err = sess.Run(cmd) if err != nil { if exitErr, ok := err.(*ssh.ExitError); ok { return NewResult(outBuffer, errBuffer, exitErr.ExitStatus()), err } else { return NewResult(outBuffer, errBuffer, 1), err } } return NewResult(outBuffer, errBuffer, 0), nil }