Skip to content

Instantly share code, notes, and snippets.

@jordanorelli
Created November 17, 2014 04:42
Show Gist options
  • Save jordanorelli/ffe9d3352c24baed9d94 to your computer and use it in GitHub Desktop.
Save jordanorelli/ffe9d3352c24baed9d94 to your computer and use it in GitHub Desktop.
package main
import (
"code.google.com/p/go.crypto/ssh"
"code.google.com/p/go.crypto/ssh/terminal"
"flag"
"fmt"
"io"
"io/ioutil"
"log"
"net"
"os"
)
const (
E_Ok int = iota
E_BadPrivateKey
E_ListenError
E_HandshakeError
)
var (
info_log *log.Logger
error_log *log.Logger
)
var options struct {
privateKeyPath string
}
func handlePassword(conn ssh.ConnMetadata, password []byte) (*ssh.Permissions, error) {
log_info("saw password request from connection: %v", conn)
log_info("client remote address: %v", conn.RemoteAddr())
log_info("client local address: %v", conn.LocalAddr())
log_info("client has server version: %s", conn.ServerVersion())
log_info("client version: %s", conn.ClientVersion())
log_info("client has session id: %v", conn.SessionID())
log_info("user: %s", conn.User())
log_info("password sent: %s", password)
var perms ssh.Permissions
return &perms, nil
}
// func handlePublicKey(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
//
// }
// func handleKeyboardAuth(conn ssh.ConnMetadata, client ssh.KeyboardInteractiveChallenge) (*ssh.Permissions, error) {
//
// }
// func logAuth(conn ssh.ConnMetadata, method string, err error) {
//
// }
func bail(status int, template string, args ...interface{}) {
if status == 0 {
fmt.Fprintf(os.Stdout, template, args...)
} else {
fmt.Fprintf(os.Stderr, template, args...)
}
os.Exit(status)
}
func log_error(template string, args ...interface{}) {
error_log.Printf(template, args...)
}
func log_info(template string, args ...interface{}) {
info_log.Printf(template, args...)
}
func handleConnection(conn net.Conn, config *ssh.ServerConfig) {
serverConn, newChan, requestChan, err := ssh.NewServerConn(conn, config)
if err != nil {
log_error("error in client handshake: %v", err)
return
}
go func() {
for request := range requestChan {
log_info("received request: %v", request)
}
}()
go func() {
for request := range newChan {
log_info("request to create a new channel of type: %v with extra data: %v", request.ChannelType(), request.ExtraData())
sshChan, requestChan, err := request.Accept()
if err != nil {
log_error("error accepting request to create new ssh channel: %v", err)
return
}
defer sshChan.Close()
go func() {
for req := range requestChan {
log_info("saw out of band request: %v", req)
}
}()
log_info("I don't know what to do with this ssh chan: %v", sshChan)
term := terminal.NewTerminal(sshChan, "> ")
for {
line, err := term.ReadLine()
switch err {
case io.EOF:
fmt.Fprintln(term, "bye")
return
case nil:
default:
log_error("error reading line from terminal: %v", err)
}
log_info(line)
}
}
}()
log_info("server conn: %v\n", serverConn)
log_info("newchan: %v\n", newChan)
log_info("requestchan: %v\n", requestChan)
if err := serverConn.Wait(); err != nil {
log_error("server conn exited with error: %v", err)
}
}
func main() {
flag.Parse()
// load up private key file
pemBytes, err := ioutil.ReadFile(options.privateKeyPath)
if err != nil {
bail(E_BadPrivateKey, "unable to read private key file: %v", err)
}
log_info("read %d pem bytes\n", len(pemBytes))
// parse private key file data
signer, err := ssh.ParsePrivateKey(pemBytes)
if err != nil {
bail(E_BadPrivateKey, "unable to parse private key data: %v", err)
}
log_info("parsed private key\n")
config := &ssh.ServerConfig{
NoClientAuth: false,
PasswordCallback: handlePassword,
// PublicKeyCallback: handlePublicKey,
// KeyboardInteractiveCallback: handleKeyboardAuth,
// AuthLogCallback: logAuth,
}
config.AddHostKey(signer)
listener, err := net.Listen("tcp", "0.0.0.0:9000")
if err != nil {
bail(E_ListenError, "unable to open tcp listener: %v", err)
}
log_info("listening on tcp port 9000\n")
for {
conn, err := listener.Accept()
if err != nil {
bail(E_ListenError, "unable to open receive connection: %v", err)
}
log_info("received incoming connection\n")
go handleConnection(conn, config)
}
}
func init() {
flag.StringVar(&options.privateKeyPath, "private-key", "test_rsa", "rsa private key")
info_log = log.New(os.Stdout, "[INFO] ", 0)
error_log = log.New(os.Stderr, "[ERROR] ", 0)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment