session_test.go 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. // Copyright 2011 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. package ssh
  5. // Session tests.
  6. import (
  7. "bytes"
  8. "io"
  9. "net"
  10. "testing"
  11. "code.google.com/p/go.crypto/ssh/terminal"
  12. )
  13. type serverType func(*serverChan)
  14. // dial constructs a new test server and returns a *ClientConn.
  15. func dial(handler serverType, t *testing.T) *ClientConn {
  16. pw := password("tiger")
  17. serverConfig.PasswordCallback = func(conn *ServerConn, user, pass string) bool {
  18. return user == "testuser" && pass == string(pw)
  19. }
  20. serverConfig.PublicKeyCallback = nil
  21. l, err := Listen("tcp", "127.0.0.1:0", serverConfig)
  22. if err != nil {
  23. t.Fatalf("unable to listen: %s", err)
  24. }
  25. go func() {
  26. defer l.Close()
  27. conn, err := l.Accept()
  28. if err != nil {
  29. t.Errorf("Unable to accept: %v", err)
  30. return
  31. }
  32. defer conn.Close()
  33. if err := conn.Handshake(); err != nil {
  34. t.Errorf("Unable to handshake: %v", err)
  35. return
  36. }
  37. for {
  38. ch, err := conn.Accept()
  39. if err == io.EOF {
  40. return
  41. }
  42. // We sometimes get ECONNRESET rather than EOF.
  43. if _, ok := err.(*net.OpError); ok {
  44. return
  45. }
  46. if err != nil {
  47. t.Errorf("Unable to accept incoming channel request: %v", err)
  48. return
  49. }
  50. if ch.ChannelType() != "session" {
  51. ch.Reject(UnknownChannelType, "unknown channel type")
  52. continue
  53. }
  54. ch.Accept()
  55. go handler(ch.(*serverChan))
  56. }
  57. t.Log("done")
  58. }()
  59. config := &ClientConfig{
  60. User: "testuser",
  61. Auth: []ClientAuth{
  62. ClientAuthPassword(pw),
  63. },
  64. }
  65. c, err := Dial("tcp", l.Addr().String(), config)
  66. if err != nil {
  67. t.Fatalf("unable to dial remote side: %s", err)
  68. }
  69. return c
  70. }
  71. // Test a simple string is returned to session.Stdout.
  72. func TestSessionShell(t *testing.T) {
  73. conn := dial(shellHandler, t)
  74. defer conn.Close()
  75. session, err := conn.NewSession()
  76. if err != nil {
  77. t.Fatalf("Unable to request new session: %s", err)
  78. }
  79. defer session.Close()
  80. stdout := new(bytes.Buffer)
  81. session.Stdout = stdout
  82. if err := session.Shell(); err != nil {
  83. t.Fatalf("Unable to execute command: %s", err)
  84. }
  85. if err := session.Wait(); err != nil {
  86. t.Fatalf("Remote command did not exit cleanly: %s", err)
  87. }
  88. actual := stdout.String()
  89. if actual != "golang" {
  90. t.Fatalf("Remote shell did not return expected string: expected=golang, actual=%s", actual)
  91. }
  92. }
  93. // TODO(dfc) add support for Std{in,err}Pipe when the Server supports it.
  94. // Test a simple string is returned via StdoutPipe.
  95. func TestSessionStdoutPipe(t *testing.T) {
  96. conn := dial(shellHandler, t)
  97. defer conn.Close()
  98. session, err := conn.NewSession()
  99. if err != nil {
  100. t.Fatalf("Unable to request new session: %s", err)
  101. }
  102. defer session.Close()
  103. stdout, err := session.StdoutPipe()
  104. if err != nil {
  105. t.Fatalf("Unable to request StdoutPipe(): %v", err)
  106. }
  107. var buf bytes.Buffer
  108. if err := session.Shell(); err != nil {
  109. t.Fatalf("Unable to execute command: %s", err)
  110. }
  111. done := make(chan bool, 1)
  112. go func() {
  113. if _, err := io.Copy(&buf, stdout); err != nil {
  114. t.Errorf("Copy of stdout failed: %v", err)
  115. }
  116. done <- true
  117. }()
  118. if err := session.Wait(); err != nil {
  119. t.Fatalf("Remote command did not exit cleanly: %s", err)
  120. }
  121. <-done
  122. actual := buf.String()
  123. if actual != "golang" {
  124. t.Fatalf("Remote shell did not return expected string: expected=golang, actual=%s", actual)
  125. }
  126. }
  127. // Test non-0 exit status is returned correctly.
  128. func TestExitStatusNonZero(t *testing.T) {
  129. conn := dial(exitStatusNonZeroHandler, t)
  130. defer conn.Close()
  131. session, err := conn.NewSession()
  132. if err != nil {
  133. t.Fatalf("Unable to request new session: %s", err)
  134. }
  135. defer session.Close()
  136. if err := session.Shell(); err != nil {
  137. t.Fatalf("Unable to execute command: %s", err)
  138. }
  139. err = session.Wait()
  140. if err == nil {
  141. t.Fatalf("expected command to fail but it didn't")
  142. }
  143. e, ok := err.(*ExitError)
  144. if !ok {
  145. t.Fatalf("expected *ExitError but got %T", err)
  146. }
  147. if e.ExitStatus() != 15 {
  148. t.Fatalf("expected command to exit with 15 but got %s", e.ExitStatus())
  149. }
  150. }
  151. // Test 0 exit status is returned correctly.
  152. func TestExitStatusZero(t *testing.T) {
  153. conn := dial(exitStatusZeroHandler, t)
  154. defer conn.Close()
  155. session, err := conn.NewSession()
  156. if err != nil {
  157. t.Fatalf("Unable to request new session: %s", err)
  158. }
  159. defer session.Close()
  160. if err := session.Shell(); err != nil {
  161. t.Fatalf("Unable to execute command: %s", err)
  162. }
  163. err = session.Wait()
  164. if err != nil {
  165. t.Fatalf("expected nil but got %s", err)
  166. }
  167. }
  168. // Test exit signal and status are both returned correctly.
  169. func TestExitSignalAndStatus(t *testing.T) {
  170. conn := dial(exitSignalAndStatusHandler, t)
  171. defer conn.Close()
  172. session, err := conn.NewSession()
  173. if err != nil {
  174. t.Fatalf("Unable to request new session: %s", err)
  175. }
  176. defer session.Close()
  177. if err := session.Shell(); err != nil {
  178. t.Fatalf("Unable to execute command: %s", err)
  179. }
  180. err = session.Wait()
  181. if err == nil {
  182. t.Fatalf("expected command to fail but it didn't")
  183. }
  184. e, ok := err.(*ExitError)
  185. if !ok {
  186. t.Fatalf("expected *ExitError but got %T", err)
  187. }
  188. if e.Signal() != "TERM" || e.ExitStatus() != 15 {
  189. t.Fatalf("expected command to exit with signal TERM and status 15 but got signal %s and status %v", e.Signal(), e.ExitStatus())
  190. }
  191. }
  192. // Test exit signal and status are both returned correctly.
  193. func TestKnownExitSignalOnly(t *testing.T) {
  194. conn := dial(exitSignalHandler, t)
  195. defer conn.Close()
  196. session, err := conn.NewSession()
  197. if err != nil {
  198. t.Fatalf("Unable to request new session: %s", err)
  199. }
  200. defer session.Close()
  201. if err := session.Shell(); err != nil {
  202. t.Fatalf("Unable to execute command: %s", err)
  203. }
  204. err = session.Wait()
  205. if err == nil {
  206. t.Fatalf("expected command to fail but it didn't")
  207. }
  208. e, ok := err.(*ExitError)
  209. if !ok {
  210. t.Fatalf("expected *ExitError but got %T", err)
  211. }
  212. if e.Signal() != "TERM" || e.ExitStatus() != 143 {
  213. t.Fatalf("expected command to exit with signal TERM and status 143 but got signal %s and status %v", e.Signal(), e.ExitStatus())
  214. }
  215. }
  216. // Test exit signal and status are both returned correctly.
  217. func TestUnknownExitSignal(t *testing.T) {
  218. conn := dial(exitSignalUnknownHandler, t)
  219. defer conn.Close()
  220. session, err := conn.NewSession()
  221. if err != nil {
  222. t.Fatalf("Unable to request new session: %s", err)
  223. }
  224. defer session.Close()
  225. if err := session.Shell(); err != nil {
  226. t.Fatalf("Unable to execute command: %s", err)
  227. }
  228. err = session.Wait()
  229. if err == nil {
  230. t.Fatalf("expected command to fail but it didn't")
  231. }
  232. e, ok := err.(*ExitError)
  233. if !ok {
  234. t.Fatalf("expected *ExitError but got %T", err)
  235. }
  236. if e.Signal() != "SYS" || e.ExitStatus() != 128 {
  237. t.Fatalf("expected command to exit with signal SYS and status 128 but got signal %s and status %v", e.Signal(), e.ExitStatus())
  238. }
  239. }
  240. // Test WaitMsg is not returned if the channel closes abruptly.
  241. func TestExitWithoutStatusOrSignal(t *testing.T) {
  242. conn := dial(exitWithoutSignalOrStatus, t)
  243. defer conn.Close()
  244. session, err := conn.NewSession()
  245. if err != nil {
  246. t.Fatalf("Unable to request new session: %s", err)
  247. }
  248. defer session.Close()
  249. if err := session.Shell(); err != nil {
  250. t.Fatalf("Unable to execute command: %s", err)
  251. }
  252. err = session.Wait()
  253. if err == nil {
  254. t.Fatalf("expected command to fail but it didn't")
  255. }
  256. _, ok := err.(*ExitError)
  257. if ok {
  258. // you can't actually test for errors.errorString
  259. // because it's not exported.
  260. t.Fatalf("expected *errorString but got %T", err)
  261. }
  262. }
  263. func TestInvalidServerMessage(t *testing.T) {
  264. conn := dial(sendInvalidRecord, t)
  265. defer conn.Close()
  266. session, err := conn.NewSession()
  267. if err != nil {
  268. t.Fatalf("Unable to request new session: %s", err)
  269. }
  270. // Make sure that we closed all the clientChans when the connection
  271. // failed.
  272. session.wait()
  273. defer session.Close()
  274. }
  275. type exitStatusMsg struct {
  276. PeersId uint32
  277. Request string
  278. WantReply bool
  279. Status uint32
  280. }
  281. type exitSignalMsg struct {
  282. PeersId uint32
  283. Request string
  284. WantReply bool
  285. Signal string
  286. CoreDumped bool
  287. Errmsg string
  288. Lang string
  289. }
  290. func newServerShell(ch *serverChan, prompt string) *ServerTerminal {
  291. term := terminal.NewTerminal(ch, prompt)
  292. return &ServerTerminal{
  293. Term: term,
  294. Channel: ch,
  295. }
  296. }
  297. func exitStatusZeroHandler(ch *serverChan) {
  298. defer ch.Close()
  299. // this string is returned to stdout
  300. shell := newServerShell(ch, "> ")
  301. shell.ReadLine()
  302. sendStatus(0, ch)
  303. }
  304. func exitStatusNonZeroHandler(ch *serverChan) {
  305. defer ch.Close()
  306. shell := newServerShell(ch, "> ")
  307. shell.ReadLine()
  308. sendStatus(15, ch)
  309. }
  310. func exitSignalAndStatusHandler(ch *serverChan) {
  311. defer ch.Close()
  312. shell := newServerShell(ch, "> ")
  313. shell.ReadLine()
  314. sendStatus(15, ch)
  315. sendSignal("TERM", ch)
  316. }
  317. func exitSignalHandler(ch *serverChan) {
  318. defer ch.Close()
  319. shell := newServerShell(ch, "> ")
  320. shell.ReadLine()
  321. sendSignal("TERM", ch)
  322. }
  323. func exitSignalUnknownHandler(ch *serverChan) {
  324. defer ch.Close()
  325. shell := newServerShell(ch, "> ")
  326. shell.ReadLine()
  327. sendSignal("SYS", ch)
  328. }
  329. func exitWithoutSignalOrStatus(ch *serverChan) {
  330. defer ch.Close()
  331. shell := newServerShell(ch, "> ")
  332. shell.ReadLine()
  333. }
  334. func shellHandler(ch *serverChan) {
  335. defer ch.Close()
  336. // this string is returned to stdout
  337. shell := newServerShell(ch, "golang")
  338. shell.ReadLine()
  339. sendStatus(0, ch)
  340. }
  341. func sendStatus(status uint32, ch *serverChan) {
  342. msg := exitStatusMsg{
  343. PeersId: ch.remoteId,
  344. Request: "exit-status",
  345. WantReply: false,
  346. Status: status,
  347. }
  348. ch.serverConn.writePacket(marshal(msgChannelRequest, msg))
  349. }
  350. func sendSignal(signal string, ch *serverChan) {
  351. sig := exitSignalMsg{
  352. PeersId: ch.remoteId,
  353. Request: "exit-signal",
  354. WantReply: false,
  355. Signal: signal,
  356. CoreDumped: false,
  357. Errmsg: "Process terminated",
  358. Lang: "en-GB-oed",
  359. }
  360. ch.serverConn.writePacket(marshal(msgChannelRequest, sig))
  361. }
  362. func sendInvalidRecord(ch *serverChan) {
  363. defer ch.Close()
  364. packet := make([]byte, 1+4+4+1)
  365. packet[0] = msgChannelData
  366. marshalUint32(packet[1:], 29348723 /* invalid channel id */)
  367. marshalUint32(packet[5:], 1)
  368. packet[9] = 42
  369. ch.serverConn.writePacket(packet)
  370. }