test_unix_test.go 5.1 KB

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