1
1
// Copyright 2013 Canonical Ltd.
2
2
// Licensed under the AGPLv3, see LICENCE file for details.
4
// Package ssh contains utilities for dealing with SSH connections,
5
// key management, and so on. All SSH-based command executions in
6
// Juju should use the Command/ScpCommand functions in this package.
8
// TODO(axw) use PuTTY/plink if it's available on Windows.
9
// TODO(axw) fallback to go.crypto/ssh if no native client is available.
10
type sshOption []string
12
var allocateTTY sshOption = []string{"-t"}
14
// TODO(axw) 2013-09-12 bug #1224230
15
// Move this to a common package for use in cmd/juju, and others.
16
var commonSSHOptions = []string{"-o", "StrictHostKeyChecking no"}
18
func sshCommand(host string, command string, options ...sshOption) *exec.Cmd {
19
args := append([]string{}, commonSSHOptions...)
20
for _, option := range options {
21
args = append(args, option...)
23
args = append(args, host, "--", command)
24
return exec.Command("ssh", args...)
20
commonOptions Option = []string{"-o", "StrictHostKeyChecking no"}
22
// AllocateTTY forces pseudo-TTY allocation, which is required,
23
// for example, for sudo password prompts on the target host.
24
AllocateTTY Option = []string{"-t"}
26
// NoPasswordAuthentication disallows password-based authentication.
27
NoPasswordAuthentication Option = []string{"-o", "PasswordAuthentication no"}
30
// sshpassWrap wraps the command/args with sshpass if it is found in $PATH
31
// and the SSHPASS environment variable is set. Otherwise, the original
32
// command/args are returned.
33
func sshpassWrap(cmd string, args []string) (string, []string) {
34
if os.Getenv("SSHPASS") != "" {
35
if path, err := exec.LookPath("sshpass"); err == nil {
36
return path, append([]string{"-e", cmd}, args...)
42
// Command initialises an os/exec.Cmd to execute the native ssh program.
44
// If the SSHPASS environment variable is set, and the sshpass program
45
// is available in $PATH, then the ssh command will be run with "sshpass -e".
46
func Command(host string, command []string, options ...Option) *exec.Cmd {
47
args := append([]string{}, commonOptions...)
48
for _, option := range options {
49
args = append(args, option...)
51
args = append(args, host)
53
args = append(args, "--")
54
args = append(args, command...)
56
bin, args := sshpassWrap("ssh", args)
57
return exec.Command(bin, args...)
60
// ScpCommand initialises an os/exec.Cmd to execute the native scp program.
62
// If the SSHPASS environment variable is set, and the sshpass program
63
// is available in $PATH, then the scp command will be run with "sshpass -e".
64
func ScpCommand(source, destination string, options ...Option) *exec.Cmd {
65
args := append([]string{}, commonOptions...)
66
for _, option := range options {
67
args = append(args, option...)
69
args = append(args, source, destination)
70
bin, args := sshpassWrap("scp", args)
71
return exec.Command(bin, args...)