blob: 4d2eabd0f40a8b003f250d25b50ab2acbece6d80 [file] [log] [blame]
Fazlul Shahriardf1b4d22012-03-27 14:40:42 -04001// 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
Dave Cheney7db43662015-02-01 17:57:17 +11005package ssh_test
Fazlul Shahriardf1b4d22012-03-27 14:40:42 -04006
7import (
8 "bytes"
Fazlul Shahriardf1b4d22012-03-27 14:40:42 -04009 "fmt"
10 "io/ioutil"
Dave Cheneyb333fd12012-04-26 20:37:06 +100011 "log"
Adam Langleyfa50e742014-04-09 13:57:52 -070012 "net"
Dave Cheneyb333fd12012-04-26 20:37:06 +100013 "net/http"
David Symonds521edf82012-03-30 15:27:01 +110014
Dave Cheney7db43662015-02-01 17:57:17 +110015 "golang.org/x/crypto/ssh"
Andrew Gerranda73c6bb2014-11-10 08:50:25 +110016 "golang.org/x/crypto/ssh/terminal"
Fazlul Shahriardf1b4d22012-03-27 14:40:42 -040017)
18
Adam Langleyfa50e742014-04-09 13:57:52 -070019func ExampleNewServerConn() {
Emmanuel Odekebde08f22016-09-18 01:01:53 -070020 // Public key authentication is done by comparing
21 // the public key of a received connection
22 // with the entries in the authorized_keys file.
23 authorizedKeysBytes, err := ioutil.ReadFile("authorized_keys")
24 if err != nil {
25 log.Fatalf("Failed to load authorized_keys, err: %v", err)
26 }
27
28 authorizedKeysMap := map[string]bool{}
29 for len(authorizedKeysBytes) > 0 {
30 pubKey, _, _, rest, err := ssh.ParseAuthorizedKey(authorizedKeysBytes)
31 if err != nil {
32 log.Fatal(err)
33 }
34
35 authorizedKeysMap[string(pubKey.Marshal())] = true
36 authorizedKeysBytes = rest
37 }
38
Fazlul Shahriardf1b4d22012-03-27 14:40:42 -040039 // An SSH server is represented by a ServerConfig, which holds
40 // certificate details and handles authentication of ServerConns.
Dave Cheney7db43662015-02-01 17:57:17 +110041 config := &ssh.ServerConfig{
Emmanuel Odekebde08f22016-09-18 01:01:53 -070042 // Remove to disable password auth.
Dave Cheney7db43662015-02-01 17:57:17 +110043 PasswordCallback: func(c ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) {
Adam Langleyfa50e742014-04-09 13:57:52 -070044 // Should use constant-time compare (or better, salt+hash) in
45 // a production setting.
46 if c.User() == "testuser" && string(pass) == "tiger" {
47 return nil, nil
48 }
49 return nil, fmt.Errorf("password rejected for %q", c.User())
Fazlul Shahriardf1b4d22012-03-27 14:40:42 -040050 },
Emmanuel Odekebde08f22016-09-18 01:01:53 -070051
52 // Remove to disable public key auth.
53 PublicKeyCallback: func(c ssh.ConnMetadata, pubKey ssh.PublicKey) (*ssh.Permissions, error) {
54 if authorizedKeysMap[string(pubKey.Marshal())] {
55 return nil, nil
56 }
57 return nil, fmt.Errorf("unknown public key for %q", c.User())
58 },
Fazlul Shahriardf1b4d22012-03-27 14:40:42 -040059 }
60
Han-Wen Nienhuys934c14f2013-09-19 14:45:31 -040061 privateBytes, err := ioutil.ReadFile("id_rsa")
Fazlul Shahriardf1b4d22012-03-27 14:40:42 -040062 if err != nil {
Mike Houston484eb342015-11-08 16:19:38 +000063 log.Fatal("Failed to load private key: ", err)
Fazlul Shahriardf1b4d22012-03-27 14:40:42 -040064 }
Han-Wen Nienhuys934c14f2013-09-19 14:45:31 -040065
Dave Cheney7db43662015-02-01 17:57:17 +110066 private, err := ssh.ParsePrivateKey(privateBytes)
Han-Wen Nienhuys934c14f2013-09-19 14:45:31 -040067 if err != nil {
Mike Houston484eb342015-11-08 16:19:38 +000068 log.Fatal("Failed to parse private key: ", err)
Fazlul Shahriardf1b4d22012-03-27 14:40:42 -040069 }
70
Han-Wen Nienhuys934c14f2013-09-19 14:45:31 -040071 config.AddHostKey(private)
72
Fazlul Shahriardf1b4d22012-03-27 14:40:42 -040073 // Once a ServerConfig has been configured, connections can be
74 // accepted.
Adam Langleyfa50e742014-04-09 13:57:52 -070075 listener, err := net.Listen("tcp", "0.0.0.0:2022")
Fazlul Shahriardf1b4d22012-03-27 14:40:42 -040076 if err != nil {
Mike Houston484eb342015-11-08 16:19:38 +000077 log.Fatal("failed to listen for connection: ", err)
Fazlul Shahriardf1b4d22012-03-27 14:40:42 -040078 }
Adam Langleyfa50e742014-04-09 13:57:52 -070079 nConn, err := listener.Accept()
Fazlul Shahriardf1b4d22012-03-27 14:40:42 -040080 if err != nil {
Mike Houston484eb342015-11-08 16:19:38 +000081 log.Fatal("failed to accept incoming connection: ", err)
Fazlul Shahriardf1b4d22012-03-27 14:40:42 -040082 }
Adam Langleyfa50e742014-04-09 13:57:52 -070083
84 // Before use, a handshake must be performed on the incoming
85 // net.Conn.
Dave Cheney7db43662015-02-01 17:57:17 +110086 _, chans, reqs, err := ssh.NewServerConn(nConn, config)
Adam Langleyfa50e742014-04-09 13:57:52 -070087 if err != nil {
Mike Houston484eb342015-11-08 16:19:38 +000088 log.Fatal("failed to handshake: ", err)
Fazlul Shahriardf1b4d22012-03-27 14:40:42 -040089 }
Adam Langleyfa50e742014-04-09 13:57:52 -070090 // The incoming Request channel must be serviced.
Dave Cheney7db43662015-02-01 17:57:17 +110091 go ssh.DiscardRequests(reqs)
Fazlul Shahriardf1b4d22012-03-27 14:40:42 -040092
Adam Langleyfa50e742014-04-09 13:57:52 -070093 // Service the incoming Channel channel.
Emmanuel Odekebde08f22016-09-18 01:01:53 -070094
95 // Service the incoming Channel channel.
Adam Langleyfa50e742014-04-09 13:57:52 -070096 for newChannel := range chans {
Fazlul Shahriardf1b4d22012-03-27 14:40:42 -040097 // Channels have a type, depending on the application level
98 // protocol intended. In the case of a shell, the type is
99 // "session" and ServerShell may be used to present a simple
100 // terminal interface.
Adam Langleyfa50e742014-04-09 13:57:52 -0700101 if newChannel.ChannelType() != "session" {
Dave Cheney7db43662015-02-01 17:57:17 +1100102 newChannel.Reject(ssh.UnknownChannelType, "unknown channel type")
Fazlul Shahriardf1b4d22012-03-27 14:40:42 -0400103 continue
104 }
Adam Langleyfa50e742014-04-09 13:57:52 -0700105 channel, requests, err := newChannel.Accept()
106 if err != nil {
Emmanuel Odekebde08f22016-09-18 01:01:53 -0700107 log.Fatalf("Could not accept channel: %v", err)
Adam Langleyfa50e742014-04-09 13:57:52 -0700108 }
109
110 // Sessions have out-of-band requests such as "shell",
111 // "pty-req" and "env". Here we handle only the
112 // "shell" request.
Dave Cheney7db43662015-02-01 17:57:17 +1100113 go func(in <-chan *ssh.Request) {
Adam Langleyfa50e742014-04-09 13:57:52 -0700114 for req := range in {
Emmanuel Odekebde08f22016-09-18 01:01:53 -0700115 req.Reply(req.Type == "shell", nil)
Adam Langleyfa50e742014-04-09 13:57:52 -0700116 }
117 }(requests)
Fazlul Shahriardf1b4d22012-03-27 14:40:42 -0400118
119 term := terminal.NewTerminal(channel, "> ")
Adam Langleyfa50e742014-04-09 13:57:52 -0700120
Fazlul Shahriardf1b4d22012-03-27 14:40:42 -0400121 go func() {
122 defer channel.Close()
123 for {
Adam Langleyfa50e742014-04-09 13:57:52 -0700124 line, err := term.ReadLine()
Fazlul Shahriardf1b4d22012-03-27 14:40:42 -0400125 if err != nil {
126 break
127 }
128 fmt.Println(line)
129 }
130 }()
131 }
132}
133
134func ExampleDial() {
Scott Bell7b428712016-04-19 13:20:54 -0700135 // An SSH client is represented with a ClientConn.
Fazlul Shahriardf1b4d22012-03-27 14:40:42 -0400136 //
137 // To authenticate with the remote server you must pass at least one
Adam Langleyfa50e742014-04-09 13:57:52 -0700138 // implementation of AuthMethod via the Auth field in ClientConfig.
Dave Cheney7db43662015-02-01 17:57:17 +1100139 config := &ssh.ClientConfig{
Fazlul Shahriardf1b4d22012-03-27 14:40:42 -0400140 User: "username",
Dave Cheney7db43662015-02-01 17:57:17 +1100141 Auth: []ssh.AuthMethod{
142 ssh.Password("yourpassword"),
Fazlul Shahriardf1b4d22012-03-27 14:40:42 -0400143 },
144 }
Dave Cheney7db43662015-02-01 17:57:17 +1100145 client, err := ssh.Dial("tcp", "yourserver.com:22", config)
Fazlul Shahriardf1b4d22012-03-27 14:40:42 -0400146 if err != nil {
Mike Houston484eb342015-11-08 16:19:38 +0000147 log.Fatal("Failed to dial: ", err)
Fazlul Shahriardf1b4d22012-03-27 14:40:42 -0400148 }
149
150 // Each ClientConn can support multiple interactive sessions,
151 // represented by a Session.
152 session, err := client.NewSession()
153 if err != nil {
Mike Houston484eb342015-11-08 16:19:38 +0000154 log.Fatal("Failed to create session: ", err)
Fazlul Shahriardf1b4d22012-03-27 14:40:42 -0400155 }
156 defer session.Close()
157
158 // Once a Session is created, you can execute a single command on
159 // the remote side using the Run method.
160 var b bytes.Buffer
161 session.Stdout = &b
162 if err := session.Run("/usr/bin/whoami"); err != nil {
Mike Houston484eb342015-11-08 16:19:38 +0000163 log.Fatal("Failed to run: " + err.Error())
Fazlul Shahriardf1b4d22012-03-27 14:40:42 -0400164 }
165 fmt.Println(b.String())
166}
Dave Cheneyb333fd12012-04-26 20:37:06 +1000167
Scott Bell7b428712016-04-19 13:20:54 -0700168func ExamplePublicKeys() {
169 // A public key may be used to authenticate against the remote
170 // server by using an unencrypted PEM-encoded private key file.
171 //
172 // If you have an encrypted private key, the crypto/x509 package
173 // can be used to decrypt it.
174 key, err := ioutil.ReadFile("/home/user/.ssh/id_rsa")
175 if err != nil {
176 log.Fatalf("unable to read private key: %v", err)
177 }
178
179 // Create the Signer for this private key.
180 signer, err := ssh.ParsePrivateKey(key)
181 if err != nil {
182 log.Fatalf("unable to parse private key: %v", err)
183 }
184
185 config := &ssh.ClientConfig{
186 User: "user",
187 Auth: []ssh.AuthMethod{
188 // Use the PublicKeys method for remote authentication.
189 ssh.PublicKeys(signer),
190 },
191 }
192
193 // Connect to the remote server and perform the SSH handshake.
194 client, err := ssh.Dial("tcp", "host.com:22", config)
195 if err != nil {
196 log.Fatalf("unable to connect: %v", err)
197 }
198 defer client.Close()
199}
200
Adam Langleyfa50e742014-04-09 13:57:52 -0700201func ExampleClient_Listen() {
Dave Cheney7db43662015-02-01 17:57:17 +1100202 config := &ssh.ClientConfig{
Dave Cheneyb333fd12012-04-26 20:37:06 +1000203 User: "username",
Dave Cheney7db43662015-02-01 17:57:17 +1100204 Auth: []ssh.AuthMethod{
205 ssh.Password("password"),
Dave Cheneyb333fd12012-04-26 20:37:06 +1000206 },
207 }
208 // Dial your ssh server.
Dave Cheney7db43662015-02-01 17:57:17 +1100209 conn, err := ssh.Dial("tcp", "localhost:22", config)
Dave Cheneyb333fd12012-04-26 20:37:06 +1000210 if err != nil {
Mike Houston484eb342015-11-08 16:19:38 +0000211 log.Fatal("unable to connect: ", err)
Dave Cheneyb333fd12012-04-26 20:37:06 +1000212 }
213 defer conn.Close()
214
215 // Request the remote side to open port 8080 on all interfaces.
216 l, err := conn.Listen("tcp", "0.0.0.0:8080")
217 if err != nil {
Mike Houston484eb342015-11-08 16:19:38 +0000218 log.Fatal("unable to register tcp forward: ", err)
Dave Cheneyb333fd12012-04-26 20:37:06 +1000219 }
220 defer l.Close()
221
222 // Serve HTTP with your SSH server acting as a reverse proxy.
223 http.Serve(l, http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
224 fmt.Fprintf(resp, "Hello world!\n")
225 }))
226}
Willem van der Schyff2fccde52012-10-21 16:16:55 +1100227
228func ExampleSession_RequestPty() {
229 // Create client config
Dave Cheney7db43662015-02-01 17:57:17 +1100230 config := &ssh.ClientConfig{
Willem van der Schyff2fccde52012-10-21 16:16:55 +1100231 User: "username",
Dave Cheney7db43662015-02-01 17:57:17 +1100232 Auth: []ssh.AuthMethod{
233 ssh.Password("password"),
Willem van der Schyff2fccde52012-10-21 16:16:55 +1100234 },
235 }
236 // Connect to ssh server
Dave Cheney7db43662015-02-01 17:57:17 +1100237 conn, err := ssh.Dial("tcp", "localhost:22", config)
Willem van der Schyff2fccde52012-10-21 16:16:55 +1100238 if err != nil {
Mike Houston484eb342015-11-08 16:19:38 +0000239 log.Fatal("unable to connect: ", err)
Willem van der Schyff2fccde52012-10-21 16:16:55 +1100240 }
241 defer conn.Close()
242 // Create a session
243 session, err := conn.NewSession()
244 if err != nil {
Mike Houston484eb342015-11-08 16:19:38 +0000245 log.Fatal("unable to create session: ", err)
Willem van der Schyff2fccde52012-10-21 16:16:55 +1100246 }
247 defer session.Close()
248 // Set up terminal modes
Dave Cheney7db43662015-02-01 17:57:17 +1100249 modes := ssh.TerminalModes{
250 ssh.ECHO: 0, // disable echoing
251 ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud
252 ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud
Willem van der Schyff2fccde52012-10-21 16:16:55 +1100253 }
254 // Request pseudo terminal
Henrik Hodne2cbd8ea2016-01-05 20:55:22 +0000255 if err := session.RequestPty("xterm", 40, 80, modes); err != nil {
Mike Houston484eb342015-11-08 16:19:38 +0000256 log.Fatal("request for pseudo terminal failed: ", err)
Willem van der Schyff2fccde52012-10-21 16:16:55 +1100257 }
258 // Start remote shell
259 if err := session.Shell(); err != nil {
Mike Houston484eb342015-11-08 16:19:38 +0000260 log.Fatal("failed to start shell: ", err)
Willem van der Schyff2fccde52012-10-21 16:16:55 +1100261 }
262}