Created
November 17, 2014 16:30
-
-
Save jordanorelli/7b690407b8b3a578b6cd to your computer and use it in GitHub Desktop.
This file contains hidden or 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 ( | |
"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 ( | |
auth_log *log.Logger | |
error_log *log.Logger | |
info_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) { | |
log_info("saw public key 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("user has ssh key of type: %s", key.Type()) | |
log_info("key is: %s", key.Marshal()) | |
var perms ssh.Permissions | |
return &perms, nil | |
} | |
// func handleKeyboardAuth(conn ssh.ConnMetadata, client ssh.KeyboardInteractiveChallenge) (*ssh.Permissions, error) { | |
// | |
// } | |
func logAuth(conn ssh.ConnMetadata, method string, err error) { | |
log_auth("client remote address: %v", conn.RemoteAddr()) | |
log_auth("client local address: %v", conn.LocalAddr()) | |
log_auth("client has server version: %s", conn.ServerVersion()) | |
log_auth("client version: %s", conn.ClientVersion()) | |
log_auth("client has session id: %v", conn.SessionID()) | |
log_auth("user: %s", conn.User()) | |
log_auth("auth method: %s", method) | |
if err != nil { | |
log_auth("auth has error: %v", err) | |
} | |
} | |
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 log_auth(template string, args ...interface{}) { | |
auth_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 of type: %s", req.Type) | |
log_info("request requires a reply: %v", req.WantReply) | |
log_info("request has payload: %s", req.Payload) | |
} | |
}() | |
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) | |
auth_log = log.New(os.Stdout, "[AUTH] ", 0) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment