OLD | NEW |
1 // Copyright 2013 Canonical Ltd. | 1 // Copyright 2013 Canonical Ltd. |
2 // Licensed under the AGPLv3, see LICENCE file for details. | 2 // Licensed under the AGPLv3, see LICENCE file for details. |
3 | 3 |
4 package ssh | 4 package ssh |
5 | 5 |
6 import ( | 6 import ( |
7 "fmt" | 7 "fmt" |
8 "io" | 8 "io" |
9 "io/ioutil" | 9 "io/ioutil" |
10 "os/user" | 10 "os/user" |
11 "strings" | 11 "strings" |
12 | 12 |
13 "code.google.com/p/go.crypto/ssh" | 13 "code.google.com/p/go.crypto/ssh" |
| 14 "github.com/juju/errgo/errors" |
14 | 15 |
15 "launchpad.net/juju-core/utils" | 16 "launchpad.net/juju-core/utils" |
16 ) | 17 ) |
17 | 18 |
18 const sshDefaultPort = 22 | 19 const sshDefaultPort = 22 |
19 | 20 |
20 // GoCryptoClient is an implementation of Client that | 21 // GoCryptoClient is an implementation of Client that |
21 // uses the embedded go.crypto/ssh SSH client. | 22 // uses the embedded go.crypto/ssh SSH client. |
22 // | 23 // |
23 // GoCryptoClient is intentionally limited in the | 24 // GoCryptoClient is intentionally limited in the |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
56 user: user, | 57 user: user, |
57 addr: fmt.Sprintf("%s:%d", host, port), | 58 addr: fmt.Sprintf("%s:%d", host, port), |
58 command: shellCommand, | 59 command: shellCommand, |
59 }} | 60 }} |
60 } | 61 } |
61 | 62 |
62 // Copy implements Client.Copy. | 63 // Copy implements Client.Copy. |
63 // | 64 // |
64 // Copy is currently unimplemented, and will always return an error. | 65 // Copy is currently unimplemented, and will always return an error. |
65 func (c *GoCryptoClient) Copy(targets, extraArgs []string, options *Options) err
or { | 66 func (c *GoCryptoClient) Copy(targets, extraArgs []string, options *Options) err
or { |
66 » return fmt.Errorf("scp command is not implemented (OpenSSH scp not avail
able in PATH)") | 67 » return errors.Newf("scp command is not implemented (OpenSSH scp not avai
lable in PATH)") |
67 } | 68 } |
68 | 69 |
69 type goCryptoCommand struct { | 70 type goCryptoCommand struct { |
70 signers []ssh.Signer | 71 signers []ssh.Signer |
71 user string | 72 user string |
72 addr string | 73 addr string |
73 command string | 74 command string |
74 stdin io.Reader | 75 stdin io.Reader |
75 stdout io.Writer | 76 stdout io.Writer |
76 stderr io.Writer | 77 stderr io.Writer |
77 conn *ssh.ClientConn | 78 conn *ssh.ClientConn |
78 sess *ssh.Session | 79 sess *ssh.Session |
79 } | 80 } |
80 | 81 |
81 var sshDial = ssh.Dial | 82 var sshDial = ssh.Dial |
82 | 83 |
83 func (c *goCryptoCommand) ensureSession() (*ssh.Session, error) { | 84 func (c *goCryptoCommand) ensureSession() (*ssh.Session, error) { |
84 if c.sess != nil { | 85 if c.sess != nil { |
85 return c.sess, nil | 86 return c.sess, nil |
86 } | 87 } |
87 if len(c.signers) == 0 { | 88 if len(c.signers) == 0 { |
88 » » return nil, fmt.Errorf("no private keys available") | 89 » » return nil, errors.Newf("no private keys available") |
89 } | 90 } |
90 if c.user == "" { | 91 if c.user == "" { |
91 currentUser, err := user.Current() | 92 currentUser, err := user.Current() |
92 if err != nil { | 93 if err != nil { |
93 » » » return nil, fmt.Errorf("getting current user: %v", err) | 94 » » » return nil, errors.Notef(err, "getting current user") |
94 } | 95 } |
95 c.user = currentUser.Username | 96 c.user = currentUser.Username |
96 } | 97 } |
97 config := &ssh.ClientConfig{ | 98 config := &ssh.ClientConfig{ |
98 User: c.user, | 99 User: c.user, |
99 Auth: []ssh.ClientAuth{ | 100 Auth: []ssh.ClientAuth{ |
100 ssh.ClientAuthKeyring(keyring{c.signers}), | 101 ssh.ClientAuthKeyring(keyring{c.signers}), |
101 }, | 102 }, |
102 } | 103 } |
103 conn, err := sshDial("tcp", c.addr, config) | 104 conn, err := sshDial("tcp", c.addr, config) |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
137 if err0 == nil { | 138 if err0 == nil { |
138 err0 = err1 | 139 err0 = err1 |
139 } | 140 } |
140 c.sess = nil | 141 c.sess = nil |
141 c.conn = nil | 142 c.conn = nil |
142 return err0 | 143 return err0 |
143 } | 144 } |
144 | 145 |
145 func (c *goCryptoCommand) Wait() error { | 146 func (c *goCryptoCommand) Wait() error { |
146 if c.sess == nil { | 147 if c.sess == nil { |
147 » » return fmt.Errorf("Command has not been started") | 148 » » return errors.Newf("Command has not been started") |
148 } | 149 } |
149 err := c.sess.Wait() | 150 err := c.sess.Wait() |
150 c.Close() | 151 c.Close() |
151 return err | 152 return err |
152 } | 153 } |
153 | 154 |
154 func (c *goCryptoCommand) Kill() error { | 155 func (c *goCryptoCommand) Kill() error { |
155 if c.sess == nil { | 156 if c.sess == nil { |
156 » » return fmt.Errorf("Command has not been started") | 157 » » return errors.Newf("Command has not been started") |
157 } | 158 } |
158 return c.sess.Signal(ssh.SIGKILL) | 159 return c.sess.Signal(ssh.SIGKILL) |
159 } | 160 } |
160 | 161 |
161 func (c *goCryptoCommand) SetStdio(stdin io.Reader, stdout, stderr io.Writer) { | 162 func (c *goCryptoCommand) SetStdio(stdin io.Reader, stdout, stderr io.Writer) { |
162 c.stdin = stdin | 163 c.stdin = stdin |
163 c.stdout = stdout | 164 c.stdout = stdout |
164 c.stderr = stderr | 165 c.stderr = stderr |
165 } | 166 } |
166 | 167 |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
199 func (k keyring) Key(i int) (ssh.PublicKey, error) { | 200 func (k keyring) Key(i int) (ssh.PublicKey, error) { |
200 if i < 0 || i >= len(k.signers) { | 201 if i < 0 || i >= len(k.signers) { |
201 // nil key marks the end of the keyring; must not return an erro
r. | 202 // nil key marks the end of the keyring; must not return an erro
r. |
202 return nil, nil | 203 return nil, nil |
203 } | 204 } |
204 return k.signers[i].PublicKey(), nil | 205 return k.signers[i].PublicKey(), nil |
205 } | 206 } |
206 | 207 |
207 func (k keyring) Sign(i int, rand io.Reader, data []byte) ([]byte, error) { | 208 func (k keyring) Sign(i int, rand io.Reader, data []byte) ([]byte, error) { |
208 if i < 0 || i >= len(k.signers) { | 209 if i < 0 || i >= len(k.signers) { |
209 » » return nil, fmt.Errorf("no key at position %d", i) | 210 » » return nil, errors.Newf("no key at position %d", i) |
210 } | 211 } |
211 return k.signers[i].Sign(rand, data) | 212 return k.signers[i].Sign(rand, data) |
212 } | 213 } |
213 | 214 |
214 func splitUserHost(s string) (user, host string) { | 215 func splitUserHost(s string) (user, host string) { |
215 userHost := strings.SplitN(s, "@", 2) | 216 userHost := strings.SplitN(s, "@", 2) |
216 if len(userHost) == 2 { | 217 if len(userHost) == 2 { |
217 return userHost[0], userHost[1] | 218 return userHost[0], userHost[1] |
218 } | 219 } |
219 return "", userHost[0] | 220 return "", userHost[0] |
220 } | 221 } |
OLD | NEW |