test_unix_test.go 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  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. "sync"
  24. "testing"
  25. "text/template"
  26. "time"
  27. "code.google.com/p/go.crypto/ssh"
  28. )
  29. const sshd_config = `
  30. Protocol 2
  31. HostKey {{.Dir}}/ssh_host_rsa_key
  32. HostKey {{.Dir}}/ssh_host_dsa_key
  33. HostKey {{.Dir}}/ssh_host_ecdsa_key
  34. Pidfile {{.Dir}}/sshd.pid
  35. #UsePrivilegeSeparation no
  36. KeyRegenerationInterval 3600
  37. ServerKeyBits 768
  38. SyslogFacility AUTH
  39. LogLevel DEBUG2
  40. LoginGraceTime 120
  41. PermitRootLogin no
  42. StrictModes no
  43. RSAAuthentication yes
  44. PubkeyAuthentication yes
  45. AuthorizedKeysFile {{.Dir}}/authorized_keys
  46. IgnoreRhosts yes
  47. RhostsRSAAuthentication no
  48. HostbasedAuthentication no
  49. `
  50. var (
  51. configTmpl template.Template
  52. sshd string // path to sshd
  53. rsakey *rsa.PrivateKey
  54. )
  55. func init() {
  56. template.Must(configTmpl.Parse(sshd_config))
  57. block, _ := pem.Decode([]byte(testClientPrivateKey))
  58. rsakey, _ = x509.ParsePKCS1PrivateKey(block.Bytes)
  59. }
  60. type server struct {
  61. t *testing.T
  62. cleanup func() // executed during Shutdown
  63. configfile string
  64. cmd *exec.Cmd
  65. output bytes.Buffer // holds stderr from sshd process
  66. }
  67. func username() string {
  68. var username string
  69. if user, err := user.Current(); err == nil {
  70. username = user.Username
  71. } else {
  72. // user.Current() currently requires cgo. If an error is
  73. // returned attempt to get the username from the environment.
  74. log.Printf("user.Current: %v; falling back on $USER", err)
  75. username = os.Getenv("USER")
  76. }
  77. if username == "" {
  78. panic("Unable to get username")
  79. }
  80. return username
  81. }
  82. func clientConfig() *ssh.ClientConfig {
  83. kc := new(keychain)
  84. kc.keys = append(kc.keys, rsakey)
  85. config := &ssh.ClientConfig{
  86. User: username(),
  87. Auth: []ssh.ClientAuth{
  88. ssh.ClientAuthKeyring(kc),
  89. },
  90. }
  91. return config
  92. }
  93. func (s *server) Dial(config *ssh.ClientConfig) *ssh.ClientConn {
  94. s.cmd = exec.Command("sshd", "-f", s.configfile, "-i")
  95. r1, w1, err := os.Pipe()
  96. if err != nil {
  97. s.t.Fatal(err)
  98. }
  99. s.cmd.Stdout = w1
  100. r2, w2, err := os.Pipe()
  101. if err != nil {
  102. s.t.Fatal(err)
  103. }
  104. s.cmd.Stdin = r2
  105. s.cmd.Stderr = os.Stderr
  106. if err := s.cmd.Start(); err != nil {
  107. s.t.Fail()
  108. s.Shutdown()
  109. s.t.Fatalf("s.cmd.Start: %v", err)
  110. }
  111. conn, err := ssh.Client(&client{wc: w2, r: r1}, config)
  112. if err != nil {
  113. s.t.Fail()
  114. s.Shutdown()
  115. s.t.Fatalf("ssh.Client: %v", err)
  116. }
  117. return conn
  118. }
  119. func (s *server) Shutdown() {
  120. if s.cmd != nil && s.cmd.Process != nil {
  121. // don't check for Kill error; if it fails it's most likely
  122. // "os: process already finished", and we don't care about that.
  123. s.cmd.Process.Kill()
  124. s.cmd.Wait()
  125. }
  126. if s.t.Failed() {
  127. // log any output from sshd process
  128. s.t.Logf("sshd: %q", s.output.String())
  129. }
  130. s.cleanup()
  131. }
  132. // client wraps a pair of Reader/WriteClosers to implement the
  133. // net.Conn interface. Importantly, client also mocks the
  134. // ability of net.Conn to support concurrent calls to Read/Write
  135. // and Close. See golang.org/issue/5138 for more details.
  136. type client struct {
  137. wc io.WriteCloser
  138. r io.Reader
  139. sync.Mutex // protects refcount and closing
  140. refcount int
  141. closing bool
  142. }
  143. var errClosing = errors.New("use of closed network connection")
  144. func (c *client) LocalAddr() net.Addr { return nil }
  145. func (c *client) RemoteAddr() net.Addr { return nil }
  146. func (c *client) SetDeadline(time.Time) error { return nil }
  147. func (c *client) SetReadDeadline(time.Time) error { return nil }
  148. func (c *client) SetWriteDeadline(time.Time) error { return nil }
  149. // incref, decref are copied from the net package (see net/fd_unix.go) to
  150. // implement the concurrent Close contract that net.Conn implementations
  151. // from that that package provide.
  152. func (c *client) incRef(closing bool) error {
  153. c.Lock()
  154. defer c.Unlock()
  155. if c.closing {
  156. return errClosing
  157. }
  158. c.refcount++
  159. if closing {
  160. c.closing = true
  161. }
  162. return nil
  163. }
  164. func (c *client) decRef() {
  165. c.Lock()
  166. defer c.Unlock()
  167. c.refcount--
  168. if c.closing && c.refcount == 0 {
  169. c.wc.Close()
  170. }
  171. }
  172. func (c *client) Close() error {
  173. if err := c.incRef(true); err != nil {
  174. return err
  175. }
  176. c.decRef()
  177. return nil
  178. }
  179. func (c *client) Read(b []byte) (int, error) {
  180. if err := c.incRef(false); err != nil {
  181. return 0, err
  182. }
  183. defer c.decRef()
  184. return c.r.Read(b)
  185. }
  186. func (c *client) Write(b []byte) (int, error) {
  187. if err := c.incRef(false); err != nil {
  188. return 0, err
  189. }
  190. defer c.decRef()
  191. return c.wc.Write(b)
  192. }
  193. // newServer returns a new mock ssh server.
  194. func newServer(t *testing.T) *server {
  195. dir, err := ioutil.TempDir("", "sshtest")
  196. if err != nil {
  197. t.Fatal(err)
  198. }
  199. f, err := os.Create(filepath.Join(dir, "sshd_config"))
  200. if err != nil {
  201. t.Fatal(err)
  202. }
  203. err = configTmpl.Execute(f, map[string]string{
  204. "Dir": dir,
  205. })
  206. if err != nil {
  207. t.Fatal(err)
  208. }
  209. f.Close()
  210. for k, v := range keys {
  211. f, err := os.OpenFile(filepath.Join(dir, k), os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0600)
  212. if err != nil {
  213. t.Fatal(err)
  214. }
  215. if _, err := f.Write([]byte(v)); err != nil {
  216. t.Fatal(err)
  217. }
  218. f.Close()
  219. }
  220. return &server{
  221. t: t,
  222. configfile: f.Name(),
  223. cleanup: func() {
  224. if err := os.RemoveAll(dir); err != nil {
  225. t.Error(err)
  226. }
  227. },
  228. }
  229. }
  230. // keychain implements the ClientKeyring interface
  231. type keychain struct {
  232. keys []interface{}
  233. }
  234. func (k *keychain) Key(i int) (interface{}, error) {
  235. if i < 0 || i >= len(k.keys) {
  236. return nil, nil
  237. }
  238. switch key := k.keys[i].(type) {
  239. case *rsa.PrivateKey:
  240. return &key.PublicKey, nil
  241. case *dsa.PrivateKey:
  242. return &key.PublicKey, nil
  243. }
  244. panic("unknown key type")
  245. }
  246. func (k *keychain) Sign(i int, rand io.Reader, data []byte) (sig []byte, err error) {
  247. hashFunc := crypto.SHA1
  248. h := hashFunc.New()
  249. h.Write(data)
  250. digest := h.Sum(nil)
  251. switch key := k.keys[i].(type) {
  252. case *rsa.PrivateKey:
  253. return rsa.SignPKCS1v15(rand, key, hashFunc, digest)
  254. }
  255. return nil, errors.New("ssh: unknown key type")
  256. }
  257. func (k *keychain) loadPEM(file string) error {
  258. buf, err := ioutil.ReadFile(file)
  259. if err != nil {
  260. return err
  261. }
  262. block, _ := pem.Decode(buf)
  263. if block == nil {
  264. return errors.New("ssh: no key found")
  265. }
  266. r, err := x509.ParsePKCS1PrivateKey(block.Bytes)
  267. if err != nil {
  268. return err
  269. }
  270. k.keys = append(k.keys, r)
  271. return nil
  272. }