Created
June 28, 2014 16:23
-
-
Save joshrendek/b20a103c5235c806e7fa to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"net" | |
"code.google.com/p/go.crypto/ssh" | |
"code.google.com/p/go.crypto/ssh/terminal" | |
) | |
func main() { | |
ExampleListen() | |
} | |
func ExampleListen() { | |
// An SSH server is represented by a ServerConfig, which holds | |
// certificate details and handles authentication of ServerConns. | |
config := &ssh.ServerConfig{ | |
PasswordCallback: func(c ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) { | |
// Should use constant-time compare (or better, salt+hash) in | |
// a production setting. | |
fmt.Printf("Username: %s | Password: %s", c.User(), string(pass)) | |
if c.User() == "testuser" && string(pass) == "tiger" { | |
return nil, nil | |
} | |
return nil, fmt.Errorf("password rejected for %q", c.User()) | |
}, | |
} | |
// Once a ServerConfig has been configured, connections can be | |
// accepted. | |
listener, err := net.Listen("tcp", "0.0.0.0:2022") | |
if err != nil { | |
panic("failed to listen for connection") | |
} | |
nConn, err := listener.Accept() | |
if err != nil { | |
panic("failed to accept incoming connection") | |
} | |
// Before use, a handshake must be performed on the incoming | |
// net.Conn. | |
_, chans, reqs, err := ssh.NewServerConn(nConn, config) | |
if err != nil { | |
panic("failed to handshake") | |
} | |
// The incoming Request channel must be serviced. | |
go ssh.DiscardRequests(reqs) | |
// A ServerConn multiplexes several channels, which must | |
// themselves be Accepted. | |
// 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 newChannel.ChannelType() != "session" { | |
newChannel.Reject(ssh.UnknownChannelType, "unknown channel type") | |
continue | |
} | |
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 *ssh.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, "> ") | |
go func() { | |
defer channel.Close() | |
for { | |
line, err := term.ReadLine() | |
if err != nil { | |
break | |
} | |
fmt.Println(line) | |
} | |
}() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment