test_unix_test.go 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  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. "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. rsakey *rsa.PrivateKey
  51. serializedHostKey []byte
  52. )
  53. func init() {
  54. template.Must(configTmpl.Parse(sshd_config))
  55. block, _ := pem.Decode([]byte(testClientPrivateKey))
  56. rsakey, _ = x509.ParsePKCS1PrivateKey(block.Bytes)
  57. block, _ = pem.Decode([]byte(keys["ssh_host_rsa_key"]))
  58. if block == nil {
  59. panic("pem.Decode ssh_host_rsa_key")
  60. }
  61. priv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
  62. if err != nil {
  63. panic("ParsePKCS1PrivateKey: " + err.Error())
  64. }
  65. serializedHostKey = ssh.MarshalPublicKey(ssh.NewRSAPublicKey(&priv.PublicKey))
  66. }
  67. type server struct {
  68. t *testing.T
  69. cleanup func() // executed during Shutdown
  70. configfile string
  71. cmd *exec.Cmd
  72. output bytes.Buffer // holds stderr from sshd process
  73. // Client half of the network connection.
  74. clientConn net.Conn
  75. }
  76. func username() string {
  77. var username string
  78. if user, err := user.Current(); err == nil {
  79. username = user.Username
  80. } else {
  81. // user.Current() currently requires cgo. If an error is
  82. // returned attempt to get the username from the environment.
  83. log.Printf("user.Current: %v; falling back on $USER", err)
  84. username = os.Getenv("USER")
  85. }
  86. if username == "" {
  87. panic("Unable to get username")
  88. }
  89. return username
  90. }
  91. type storedHostKey struct {
  92. // keys map from an algorithm string to binary key data.
  93. keys map[string][]byte
  94. }
  95. func (k *storedHostKey) Add(algo string, public []byte) {
  96. if k.keys == nil {
  97. k.keys = map[string][]byte{}
  98. }
  99. k.keys[algo] = append([]byte(nil), public...)
  100. }
  101. func (k *storedHostKey) Check(addr string, remote net.Addr, algo string, key []byte) error {
  102. if k.keys == nil || bytes.Compare(key, k.keys[algo]) != 0 {
  103. return errors.New("host key mismatch")
  104. }
  105. return nil
  106. }
  107. func clientConfig() *ssh.ClientConfig {
  108. keyChecker := storedHostKey{}
  109. keyChecker.Add("ssh-rsa", serializedHostKey)
  110. kc := new(keychain)
  111. kc.keys = append(kc.keys, rsakey)
  112. config := &ssh.ClientConfig{
  113. User: username(),
  114. Auth: []ssh.ClientAuth{
  115. ssh.ClientAuthKeyring(kc),
  116. },
  117. HostKeyChecker: &keyChecker,
  118. }
  119. return config
  120. }
  121. // unixConnection creates two halves of a connected net.UnixConn. It
  122. // is used for connecting the Go SSH client with sshd without opening
  123. // ports.
  124. func unixConnection() (*net.UnixConn, *net.UnixConn, error) {
  125. dir, err := ioutil.TempDir("", "unixConnection")
  126. if err != nil {
  127. return nil, nil, err
  128. }
  129. defer os.Remove(dir)
  130. addr := filepath.Join(dir, "ssh")
  131. listener, err := net.Listen("unix", addr)
  132. if err != nil {
  133. return nil, nil, err
  134. }
  135. defer listener.Close()
  136. c1, err := net.Dial("unix", addr)
  137. if err != nil {
  138. return nil, nil, err
  139. }
  140. c2, err := listener.Accept()
  141. if err != nil {
  142. c1.Close()
  143. return nil, nil, err
  144. }
  145. return c1.(*net.UnixConn), c2.(*net.UnixConn), nil
  146. }
  147. func (s *server) TryDial(config *ssh.ClientConfig) (*ssh.ClientConn, error) {
  148. sshd, err := exec.LookPath("sshd")
  149. if err != nil {
  150. s.t.Skipf("skipping test: %v", err)
  151. }
  152. c1, c2, err := unixConnection()
  153. if err != nil {
  154. s.t.Fatalf("unixConnection: %v", err)
  155. }
  156. s.cmd = exec.Command(sshd, "-f", s.configfile, "-i", "-e")
  157. f, err := c2.File()
  158. if err != nil {
  159. s.t.Fatalf("UnixConn.File: %v", err)
  160. }
  161. defer f.Close()
  162. s.cmd.Stdin = f
  163. s.cmd.Stdout = f
  164. s.cmd.Stderr = &s.output
  165. if err := s.cmd.Start(); err != nil {
  166. s.t.Fail()
  167. s.Shutdown()
  168. s.t.Fatalf("s.cmd.Start: %v", err)
  169. }
  170. s.clientConn = c1
  171. return ssh.Client(c1, config)
  172. }
  173. func (s *server) Dial(config *ssh.ClientConfig) *ssh.ClientConn {
  174. conn, err := s.TryDial(config)
  175. if err != nil {
  176. s.t.Fail()
  177. s.Shutdown()
  178. s.t.Fatalf("ssh.Client: %v", err)
  179. }
  180. return conn
  181. }
  182. func (s *server) Shutdown() {
  183. if s.cmd != nil && s.cmd.Process != nil {
  184. // Don't check for errors; if it fails it's most
  185. // likely "os: process already finished", and we don't
  186. // care about that. Use os.Interrupt, so child
  187. // processes are killed too.
  188. s.cmd.Process.Signal(os.Interrupt)
  189. s.cmd.Wait()
  190. }
  191. if s.t.Failed() {
  192. // log any output from sshd process
  193. s.t.Logf("sshd: %s", s.output.String())
  194. }
  195. s.cleanup()
  196. }
  197. // newServer returns a new mock ssh server.
  198. func newServer(t *testing.T) *server {
  199. dir, err := ioutil.TempDir("", "sshtest")
  200. if err != nil {
  201. t.Fatal(err)
  202. }
  203. f, err := os.Create(filepath.Join(dir, "sshd_config"))
  204. if err != nil {
  205. t.Fatal(err)
  206. }
  207. err = configTmpl.Execute(f, map[string]string{
  208. "Dir": dir,
  209. })
  210. if err != nil {
  211. t.Fatal(err)
  212. }
  213. f.Close()
  214. for k, v := range keys {
  215. f, err := os.OpenFile(filepath.Join(dir, k), os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0600)
  216. if err != nil {
  217. t.Fatal(err)
  218. }
  219. if _, err := f.Write([]byte(v)); err != nil {
  220. t.Fatal(err)
  221. }
  222. f.Close()
  223. }
  224. return &server{
  225. t: t,
  226. configfile: f.Name(),
  227. cleanup: func() {
  228. if err := os.RemoveAll(dir); err != nil {
  229. t.Error(err)
  230. }
  231. },
  232. }
  233. }
  234. // keychain implements the ClientKeyring interface
  235. type keychain struct {
  236. keys []interface{}
  237. }
  238. func (k *keychain) Key(i int) (ssh.PublicKey, error) {
  239. if i < 0 || i >= len(k.keys) {
  240. return nil, nil
  241. }
  242. switch key := k.keys[i].(type) {
  243. case *rsa.PrivateKey:
  244. return ssh.NewRSAPublicKey(&key.PublicKey), nil
  245. case *dsa.PrivateKey:
  246. return ssh.NewDSAPublicKey(&key.PublicKey), nil
  247. }
  248. panic("unknown key type")
  249. }
  250. func (k *keychain) Sign(i int, rand io.Reader, data []byte) (sig []byte, err error) {
  251. hashFunc := crypto.SHA1
  252. h := hashFunc.New()
  253. h.Write(data)
  254. digest := h.Sum(nil)
  255. switch key := k.keys[i].(type) {
  256. case *rsa.PrivateKey:
  257. return rsa.SignPKCS1v15(rand, key, hashFunc, digest)
  258. }
  259. return nil, errors.New("ssh: unknown key type")
  260. }
  261. func (k *keychain) loadPEM(file string) error {
  262. buf, err := ioutil.ReadFile(file)
  263. if err != nil {
  264. return err
  265. }
  266. block, _ := pem.Decode(buf)
  267. if block == nil {
  268. return errors.New("ssh: no key found")
  269. }
  270. r, err := x509.ParsePKCS1PrivateKey(block.Bytes)
  271. if err != nil {
  272. return err
  273. }
  274. k.keys = append(k.keys, r)
  275. return nil
  276. }