diff options
| author | Adam Langley <agl@golang.org> | 2014-04-09 13:57:52 -0700 |
|---|---|---|
| committer | Adam Langley <agl@golang.org> | 2014-04-09 13:57:52 -0700 |
| commit | fa50e7408b9ef89ff2965535b59f1a0010c0770b (patch) | |
| tree | e045a3f48f9ffd3bb712002f8f9f6fd489e8f7ef /ssh/example_test.go | |
| parent | 8f45c680ceb25c200b8c301d9184532aeb7cb36e (diff) | |
| download | go-x-crypto-fa50e7408b9ef89ff2965535b59f1a0010c0770b.tar.xz | |
go.crypto/ssh: import gosshnew.
See https://groups.google.com/d/msg/Golang-nuts/AoVxQ4bB5XQ/i8kpMxdbVlEJ
R=hanwen
CC=golang-codereviews
https://golang.org/cl/86190043
Diffstat (limited to 'ssh/example_test.go')
| -rw-r--r-- | ssh/example_test.go | 93 |
1 files changed, 56 insertions, 37 deletions
diff --git a/ssh/example_test.go b/ssh/example_test.go index a88a677..d9d6a54 100644 --- a/ssh/example_test.go +++ b/ssh/example_test.go @@ -9,17 +9,23 @@ import ( "fmt" "io/ioutil" "log" + "net" "net/http" "code.google.com/p/go.crypto/ssh/terminal" ) -func ExampleListen() { +func ExampleNewServerConn() { // An SSH server is represented by a ServerConfig, which holds // certificate details and handles authentication of ServerConns. config := &ServerConfig{ - PasswordCallback: func(conn *ServerConn, user, pass string) bool { - return user == "testuser" && pass == "tiger" + PasswordCallback: func(c ConnMetadata, pass []byte) (*Permissions, error) { + // Should use constant-time compare (or better, salt+hash) in + // a production setting. + if c.User() == "testuser" && string(pass) == "tiger" { + return nil, nil + } + return nil, fmt.Errorf("password rejected for %q", c.User()) }, } @@ -37,50 +43,65 @@ func ExampleListen() { // Once a ServerConfig has been configured, connections can be // accepted. - listener, err := Listen("tcp", "0.0.0.0:2022", config) + listener, err := net.Listen("tcp", "0.0.0.0:2022") if err != nil { panic("failed to listen for connection") } - sConn, err := listener.Accept() + nConn, err := listener.Accept() if err != nil { panic("failed to accept incoming connection") } - if err := sConn.Handshake(); err != nil { + + // Before use, a handshake must be performed on the incoming + // net.Conn. + _, chans, reqs, err := NewServerConn(nConn, config) + if err != nil { panic("failed to handshake") } + // The incoming Request channel must be serviced. + go DiscardRequests(reqs) - // A ServerConn multiplexes several channels, which must - // themselves be Accepted. - for { - // Accept reads from the connection, demultiplexes packets - // to their corresponding channels and returns when a new - // channel request is seen. Some goroutine must always be - // calling Accept; otherwise no messages will be forwarded - // to the channels. - channel, err := sConn.Accept() - if err != nil { - panic("error from Accept") - } - + // Service the incoming Channel channel. + for newChannel := range chans { // Channels have a type, depending on the application level // protocol intended. In the case of a shell, the type is // "session" and ServerShell may be used to present a simple // terminal interface. - if channel.ChannelType() != "session" { - channel.Reject(UnknownChannelType, "unknown channel type") + if newChannel.ChannelType() != "session" { + newChannel.Reject(UnknownChannelType, "unknown channel type") continue } - channel.Accept() + channel, requests, err := newChannel.Accept() + if err != nil { + panic("could not accept channel.") + } + + // Sessions have out-of-band requests such as "shell", + // "pty-req" and "env". Here we handle only the + // "shell" request. + go func(in <-chan *Request) { + for req := range in { + ok := false + switch req.Type { + case "shell": + ok = true + if len(req.Payload) > 0 { + // We don't accept any + // commands, only the + // default shell. + ok = false + } + } + req.Reply(ok, nil) + } + }(requests) term := terminal.NewTerminal(channel, "> ") - serverTerm := &ServerTerminal{ - Term: term, - Channel: channel, - } + go func() { defer channel.Close() for { - line, err := serverTerm.ReadLine() + line, err := term.ReadLine() if err != nil { break } @@ -95,13 +116,11 @@ func ExampleDial() { // the "password" authentication method is supported. // // To authenticate with the remote server you must pass at least one - // implementation of ClientAuth via the Auth field in ClientConfig. + // implementation of AuthMethod via the Auth field in ClientConfig. config := &ClientConfig{ User: "username", - Auth: []ClientAuth{ - // ClientAuthPassword wraps a ClientPassword implementation - // in a type that implements ClientAuth. - ClientAuthPassword(password("yourpassword")), + Auth: []AuthMethod{ + Password("yourpassword"), }, } client, err := Dial("tcp", "yourserver.com:22", config) @@ -127,11 +146,11 @@ func ExampleDial() { fmt.Println(b.String()) } -func ExampleClientConn_Listen() { +func ExampleClient_Listen() { config := &ClientConfig{ User: "username", - Auth: []ClientAuth{ - ClientAuthPassword(password("password")), + Auth: []AuthMethod{ + Password("password"), }, } // Dial your ssh server. @@ -158,8 +177,8 @@ func ExampleSession_RequestPty() { // Create client config config := &ClientConfig{ User: "username", - Auth: []ClientAuth{ - ClientAuthPassword(password("password")), + Auth: []AuthMethod{ + Password("password"), }, } // Connect to ssh server |
