test_unix_test.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. // Copyright 2012 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. // +build darwin freebsd linux netbsd openbsd
  5. package test
  6. // functional test harness for unix.
  7. import (
  8. "bytes"
  9. "crypto"
  10. "crypto/dsa"
  11. "crypto/rsa"
  12. "crypto/x509"
  13. "encoding/pem"
  14. "errors"
  15. "io"
  16. "io/ioutil"
  17. "net"
  18. "os"
  19. "os/exec"
  20. "os/user"
  21. "path/filepath"
  22. "testing"
  23. "text/template"
  24. "time"
  25. "code.google.com/p/go.crypto/ssh"
  26. )
  27. const sshd_config = `
  28. Protocol 2
  29. HostKey {{.Dir}}/ssh_host_rsa_key
  30. HostKey {{.Dir}}/ssh_host_dsa_key
  31. HostKey {{.Dir}}/ssh_host_ecdsa_key
  32. Pidfile {{.Dir}}/sshd.pid
  33. #UsePrivilegeSeparation no
  34. KeyRegenerationInterval 3600
  35. ServerKeyBits 768
  36. SyslogFacility AUTH
  37. LogLevel DEBUG2
  38. LoginGraceTime 120
  39. PermitRootLogin no
  40. StrictModes no
  41. RSAAuthentication yes
  42. PubkeyAuthentication yes
  43. AuthorizedKeysFile {{.Dir}}/authorized_keys
  44. IgnoreRhosts yes
  45. RhostsRSAAuthentication no
  46. HostbasedAuthentication no
  47. `
  48. var (
  49. configTmpl template.Template
  50. sshd string // path to sshd
  51. rsakey *rsa.PrivateKey
  52. )
  53. func init() {
  54. template.Must(configTmpl.Parse(sshd_config))
  55. block, _ := pem.Decode([]byte(testClientPrivateKey))
  56. rsakey, _ = x509.ParsePKCS1PrivateKey(block.Bytes)
  57. }
  58. type server struct {
  59. t *testing.T
  60. cleanup func() // executed during Shutdown
  61. configfile string
  62. cmd *exec.Cmd
  63. output bytes.Buffer // holds stderr from sshd process
  64. }
  65. func username() string {
  66. var username string
  67. if user, err := user.Current(); err == nil {
  68. username = user.Username
  69. } else {
  70. // user.Current() currently requires cgo. If an error is
  71. // returned attempt to get the username from the environment.
  72. username = os.Getenv("USER")
  73. }
  74. if username == "" {
  75. panic("Unable to get username")
  76. }
  77. return username
  78. }
  79. func clientConfig() *ssh.ClientConfig {
  80. kc := new(keychain)
  81. kc.keys = append(kc.keys, rsakey)
  82. config := &ssh.ClientConfig{
  83. User: username(),
  84. Auth: []ssh.ClientAuth{
  85. ssh.ClientAuthKeyring(kc),
  86. },
  87. }
  88. return config
  89. }
  90. func (s *server) Dial(config *ssh.ClientConfig) *ssh.ClientConn {
  91. s.cmd = exec.Command("sshd", "-f", s.configfile, "-i")
  92. stdin, err := s.cmd.StdinPipe()
  93. if err != nil {
  94. s.t.Fatal(err)
  95. }
  96. stdout, err := s.cmd.StdoutPipe()
  97. if err != nil {
  98. s.t.Fatal(err)
  99. }
  100. s.cmd.Stderr = os.Stderr // &s.output
  101. err = s.cmd.Start()
  102. if err != nil {
  103. s.t.FailNow()
  104. s.Shutdown()
  105. s.t.Fatal(err)
  106. }
  107. conn, err := ssh.Client(&client{stdin, stdout}, config)
  108. if err != nil {
  109. s.t.FailNow()
  110. s.Shutdown()
  111. s.t.Fatal(err)
  112. }
  113. return conn
  114. }
  115. func (s *server) Shutdown() {
  116. if s.cmd.Process != nil {
  117. if err := s.cmd.Process.Kill(); err != nil {
  118. s.t.Error(err)
  119. }
  120. }
  121. if s.t.Failed() {
  122. // log any output from sshd process
  123. s.t.Log(s.output.String())
  124. }
  125. s.cleanup()
  126. }
  127. // client wraps a pair of Reader/WriteClosers to implement the
  128. // net.Conn interface.
  129. type client struct {
  130. io.WriteCloser
  131. io.Reader
  132. }
  133. func (c *client) LocalAddr() net.Addr { return nil }
  134. func (c *client) RemoteAddr() net.Addr { return nil }
  135. func (c *client) SetDeadline(time.Time) error { return nil }
  136. func (c *client) SetReadDeadline(time.Time) error { return nil }
  137. func (c *client) SetWriteDeadline(time.Time) error { return nil }
  138. // newServer returns a new mock ssh server.
  139. func newServer(t *testing.T) *server {
  140. dir, err := ioutil.TempDir("", "sshtest")
  141. if err != nil {
  142. t.Fatal(err)
  143. }
  144. f, err := os.Create(filepath.Join(dir, "sshd_config"))
  145. if err != nil {
  146. t.Fatal(err)
  147. }
  148. err = configTmpl.Execute(f, map[string]string{
  149. "Dir": dir,
  150. })
  151. if err != nil {
  152. t.Fatal(err)
  153. }
  154. f.Close()
  155. for k, v := range keys {
  156. f, err := os.OpenFile(filepath.Join(dir, k), os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0600)
  157. if err != nil {
  158. t.Fatal(err)
  159. }
  160. if _, err := f.Write([]byte(v)); err != nil {
  161. t.Fatal(err)
  162. }
  163. f.Close()
  164. }
  165. return &server{
  166. t: t,
  167. configfile: f.Name(),
  168. cleanup: func() {
  169. if err := os.RemoveAll(dir); err != nil {
  170. t.Error(err)
  171. }
  172. },
  173. }
  174. }
  175. // keychain implements the ClientKeyring interface
  176. type keychain struct {
  177. keys []interface{}
  178. }
  179. func (k *keychain) Key(i int) (interface{}, error) {
  180. if i < 0 || i >= len(k.keys) {
  181. return nil, nil
  182. }
  183. switch key := k.keys[i].(type) {
  184. case *rsa.PrivateKey:
  185. return &key.PublicKey, nil
  186. case *dsa.PrivateKey:
  187. return &key.PublicKey, nil
  188. }
  189. panic("unknown key type")
  190. }
  191. func (k *keychain) Sign(i int, rand io.Reader, data []byte) (sig []byte, err error) {
  192. hashFunc := crypto.SHA1
  193. h := hashFunc.New()
  194. h.Write(data)
  195. digest := h.Sum(nil)
  196. switch key := k.keys[i].(type) {
  197. case *rsa.PrivateKey:
  198. return rsa.SignPKCS1v15(rand, key, hashFunc, digest)
  199. }
  200. return nil, errors.New("ssh: unknown key type")
  201. }
  202. func (k *keychain) loadPEM(file string) error {
  203. buf, err := ioutil.ReadFile(file)
  204. if err != nil {
  205. return err
  206. }
  207. block, _ := pem.Decode(buf)
  208. if block == nil {
  209. return errors.New("ssh: no key found")
  210. }
  211. r, err := x509.ParsePKCS1PrivateKey(block.Bytes)
  212. if err != nil {
  213. return err
  214. }
  215. k.keys = append(k.keys, r)
  216. return nil
  217. }