You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

263 lines
7.0 KiB

  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_test
  5. import (
  6. "bytes"
  7. "fmt"
  8. "io/ioutil"
  9. "log"
  10. "net"
  11. "net/http"
  12. "golang.org/x/crypto/ssh"
  13. "golang.org/x/crypto/ssh/terminal"
  14. )
  15. func ExampleNewServerConn() {
  16. // Public key authentication is done by comparing
  17. // the public key of a received connection
  18. // with the entries in the authorized_keys file.
  19. authorizedKeysBytes, err := ioutil.ReadFile("authorized_keys")
  20. if err != nil {
  21. log.Fatalf("Failed to load authorized_keys, err: %v", err)
  22. }
  23. authorizedKeysMap := map[string]bool{}
  24. for len(authorizedKeysBytes) > 0 {
  25. pubKey, _, _, rest, err := ssh.ParseAuthorizedKey(authorizedKeysBytes)
  26. if err != nil {
  27. log.Fatal(err)
  28. }
  29. authorizedKeysMap[string(pubKey.Marshal())] = true
  30. authorizedKeysBytes = rest
  31. }
  32. // An SSH server is represented by a ServerConfig, which holds
  33. // certificate details and handles authentication of ServerConns.
  34. config := &ssh.ServerConfig{
  35. // Remove to disable password auth.
  36. PasswordCallback: func(c ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) {
  37. // Should use constant-time compare (or better, salt+hash) in
  38. // a production setting.
  39. if c.User() == "testuser" && string(pass) == "tiger" {
  40. return nil, nil
  41. }
  42. return nil, fmt.Errorf("password rejected for %q", c.User())
  43. },
  44. // Remove to disable public key auth.
  45. PublicKeyCallback: func(c ssh.ConnMetadata, pubKey ssh.PublicKey) (*ssh.Permissions, error) {
  46. if authorizedKeysMap[string(pubKey.Marshal())] {
  47. return nil, nil
  48. }
  49. return nil, fmt.Errorf("unknown public key for %q", c.User())
  50. },
  51. }
  52. privateBytes, err := ioutil.ReadFile("id_rsa")
  53. if err != nil {
  54. log.Fatal("Failed to load private key: ", err)
  55. }
  56. private, err := ssh.ParsePrivateKey(privateBytes)
  57. if err != nil {
  58. log.Fatal("Failed to parse private key: ", err)
  59. }
  60. config.AddHostKey(private)
  61. // Once a ServerConfig has been configured, connections can be
  62. // accepted.
  63. listener, err := net.Listen("tcp", "0.0.0.0:2022")
  64. if err != nil {
  65. log.Fatal("failed to listen for connection: ", err)
  66. }
  67. nConn, err := listener.Accept()
  68. if err != nil {
  69. log.Fatal("failed to accept incoming connection: ", err)
  70. }
  71. // Before use, a handshake must be performed on the incoming
  72. // net.Conn.
  73. _, chans, reqs, err := ssh.NewServerConn(nConn, config)
  74. if err != nil {
  75. log.Fatal("failed to handshake: ", err)
  76. }
  77. // The incoming Request channel must be serviced.
  78. go ssh.DiscardRequests(reqs)
  79. // Service the incoming Channel channel.
  80. // Service the incoming Channel channel.
  81. for newChannel := range chans {
  82. // Channels have a type, depending on the application level
  83. // protocol intended. In the case of a shell, the type is
  84. // "session" and ServerShell may be used to present a simple
  85. // terminal interface.
  86. if newChannel.ChannelType() != "session" {
  87. newChannel.Reject(ssh.UnknownChannelType, "unknown channel type")
  88. continue
  89. }
  90. channel, requests, err := newChannel.Accept()
  91. if err != nil {
  92. log.Fatalf("Could not accept channel: %v", err)
  93. }
  94. // Sessions have out-of-band requests such as "shell",
  95. // "pty-req" and "env". Here we handle only the
  96. // "shell" request.
  97. go func(in <-chan *ssh.Request) {
  98. for req := range in {
  99. req.Reply(req.Type == "shell", nil)
  100. }
  101. }(requests)
  102. term := terminal.NewTerminal(channel, "> ")
  103. go func() {
  104. defer channel.Close()
  105. for {
  106. line, err := term.ReadLine()
  107. if err != nil {
  108. break
  109. }
  110. fmt.Println(line)
  111. }
  112. }()
  113. }
  114. }
  115. func ExampleDial() {
  116. // An SSH client is represented with a ClientConn.
  117. //
  118. // To authenticate with the remote server you must pass at least one
  119. // implementation of AuthMethod via the Auth field in ClientConfig.
  120. config := &ssh.ClientConfig{
  121. User: "username",
  122. Auth: []ssh.AuthMethod{
  123. ssh.Password("yourpassword"),
  124. },
  125. }
  126. client, err := ssh.Dial("tcp", "yourserver.com:22", config)
  127. if err != nil {
  128. log.Fatal("Failed to dial: ", err)
  129. }
  130. // Each ClientConn can support multiple interactive sessions,
  131. // represented by a Session.
  132. session, err := client.NewSession()
  133. if err != nil {
  134. log.Fatal("Failed to create session: ", err)
  135. }
  136. defer session.Close()
  137. // Once a Session is created, you can execute a single command on
  138. // the remote side using the Run method.
  139. var b bytes.Buffer
  140. session.Stdout = &b
  141. if err := session.Run("/usr/bin/whoami"); err != nil {
  142. log.Fatal("Failed to run: " + err.Error())
  143. }
  144. fmt.Println(b.String())
  145. }
  146. func ExamplePublicKeys() {
  147. // A public key may be used to authenticate against the remote
  148. // server by using an unencrypted PEM-encoded private key file.
  149. //
  150. // If you have an encrypted private key, the crypto/x509 package
  151. // can be used to decrypt it.
  152. key, err := ioutil.ReadFile("/home/user/.ssh/id_rsa")
  153. if err != nil {
  154. log.Fatalf("unable to read private key: %v", err)
  155. }
  156. // Create the Signer for this private key.
  157. signer, err := ssh.ParsePrivateKey(key)
  158. if err != nil {
  159. log.Fatalf("unable to parse private key: %v", err)
  160. }
  161. config := &ssh.ClientConfig{
  162. User: "user",
  163. Auth: []ssh.AuthMethod{
  164. // Use the PublicKeys method for remote authentication.
  165. ssh.PublicKeys(signer),
  166. },
  167. }
  168. // Connect to the remote server and perform the SSH handshake.
  169. client, err := ssh.Dial("tcp", "host.com:22", config)
  170. if err != nil {
  171. log.Fatalf("unable to connect: %v", err)
  172. }
  173. defer client.Close()
  174. }
  175. func ExampleClient_Listen() {
  176. config := &ssh.ClientConfig{
  177. User: "username",
  178. Auth: []ssh.AuthMethod{
  179. ssh.Password("password"),
  180. },
  181. }
  182. // Dial your ssh server.
  183. conn, err := ssh.Dial("tcp", "localhost:22", config)
  184. if err != nil {
  185. log.Fatal("unable to connect: ", err)
  186. }
  187. defer conn.Close()
  188. // Request the remote side to open port 8080 on all interfaces.
  189. l, err := conn.Listen("tcp", "0.0.0.0:8080")
  190. if err != nil {
  191. log.Fatal("unable to register tcp forward: ", err)
  192. }
  193. defer l.Close()
  194. // Serve HTTP with your SSH server acting as a reverse proxy.
  195. http.Serve(l, http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
  196. fmt.Fprintf(resp, "Hello world!\n")
  197. }))
  198. }
  199. func ExampleSession_RequestPty() {
  200. // Create client config
  201. config := &ssh.ClientConfig{
  202. User: "username",
  203. Auth: []ssh.AuthMethod{
  204. ssh.Password("password"),
  205. },
  206. }
  207. // Connect to ssh server
  208. conn, err := ssh.Dial("tcp", "localhost:22", config)
  209. if err != nil {
  210. log.Fatal("unable to connect: ", err)
  211. }
  212. defer conn.Close()
  213. // Create a session
  214. session, err := conn.NewSession()
  215. if err != nil {
  216. log.Fatal("unable to create session: ", err)
  217. }
  218. defer session.Close()
  219. // Set up terminal modes
  220. modes := ssh.TerminalModes{
  221. ssh.ECHO: 0, // disable echoing
  222. ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud
  223. ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud
  224. }
  225. // Request pseudo terminal
  226. if err := session.RequestPty("xterm", 40, 80, modes); err != nil {
  227. log.Fatal("request for pseudo terminal failed: ", err)
  228. }
  229. // Start remote shell
  230. if err := session.Shell(); err != nil {
  231. log.Fatal("failed to start shell: ", err)
  232. }
  233. }