ssh

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 4, 2017 License: BSD-3-Clause Imports: 14 Imported by: 0

README

gliderlabs/ssh

Slack GoDoc Go Report Card

This Go package wraps the crypto/ssh package with a higher-level API for building SSH servers. The goal of the API was to make it as simple as using net/http, so the API is very similar:

 package main
 
 import (
     "github.com/gliderlabs/ssh"
     "io"
     "log"
 )
 
 func main() {
     ssh.Handle(func(s ssh.Session) {
         io.WriteString(s, "Hello world\n")
     })  
 
     log.Fatal(ssh.ListenAndServe(":2222", nil))
 }

This package was built after working on nearly a dozen projects using SSH and collaborating with @shazow (known for ssh-chat).

Usage

See GoDoc reference.

Testing

We could use some help figuring out the best way to test this library. Since there is very little functionality it's adding, it doesn't seem appropriate to duplicate the crypto/ssh tests, however, maybe that's actually the best idea. Perform the same tests using this API.

Contributing

Pull requests are welcome! However, since this project is very much about API design, please submit API changes as issues to discuss before submitting PRs.

Also, you can join our Slack to discuss as well.

License

BSD

Documentation

Overview

Package ssh wraps the crypto/ssh package with a higher-level API for building SSH servers. The goal of the API was to make it as simple as using net/http, so the API is very similar.

You should be able to build any SSH server using only this package, which wraps relevant types and some functions from crypto/ssh. However, you still need to use crypto/ssh for building SSH clients.

ListenAndServe starts an SSH server with a given address, handler, and options. The handler is usually nil, which means to use DefaultHandler. Handle sets DefaultHandler:

ssh.Handle(func(s ssh.Session) {
    io.WriteString(s, "Hello world\n")
})

log.Fatal(ssh.ListenAndServe(":2222", nil))

If you don't specify a host key, it will generate one every time. This is convenient except you'll have to deal with clients being confused that the host key is different. It's a better idea to generate or point to an existing key on your system:

log.Fatal(ssh.ListenAndServe(":2222", nil, ssh.HostKeyFile("/Users/progrium/.ssh/id_rsa")))

Although all options have functional option helpers, another way to control the server's behavior is by creating a custom Server:

s := &ssh.Server{
    Addr:             ":2222",
    Handler:          sessionHandler,
    PublicKeyHandler: authHandler,
}
s.AddHostKey(hostKeySigner)

log.Fatal(s.ListenAndServe())

This package automatically handles basic SSH requests like setting environment variables, requesting PTY, and changing window size. These requests are processed, responded to, and any relevant state is updated. This state is then exposed to you via the Session interface.

The one big feature missing from the Session abstraction is signals. This was started, but not completed. Pull Requests welcome!

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Handle

func Handle(handler Handler)

Handle registers the handler as the DefaultHandler.

func KeysEqual

func KeysEqual(ak, bk PublicKey) bool

KeysEqual is constant time compare of the keys to avoid timing attacks.

func ListenAndServe

func ListenAndServe(addr string, handler Handler, options ...Option) error

ListenAndServe listens on the TCP network address addr and then calls Serve with handler to handle sessions on incoming connections. Handler is typically nil, in which case the DefaultHandler is used.

Example
package main

import (
	"io"

	"github.com/gliderlabs/ssh"
)

func main() {
	ssh.ListenAndServe(":2222", func(s ssh.Session) {
		io.WriteString(s, "Hello world\n")
	})
}
Output:

func Serve

func Serve(l net.Listener, handler Handler, options ...Option) error

Serve accepts incoming SSH connections on the listener l, creating a new connection goroutine for each. The connection goroutines read requests and then calls handler to handle sessions. Handler is typically nil, in which case the DefaultHandler is used.

Types

type Handler

type Handler func(Session)

Handler is a callback for handling established SSH sessions.

var DefaultHandler Handler

DefaultHandler is the default Handler used by Serve.

type Option

type Option func(*Server) error

Option is a functional option handler for Server.

func HostKeyFile

func HostKeyFile(filepath string) Option

HostKeyFile returns a functional option that adds HostSigners to the server from a PEM file at filepath.

Example
package main

import (
	"github.com/gliderlabs/ssh"
)

func main() {
	ssh.ListenAndServe(":2222", nil, ssh.HostKeyFile("/path/to/host/key"))
}
Output:

func HostKeyPEM

func HostKeyPEM(bytes []byte) Option

HostKeyPEM returns a functional option that adds HostSigners to the server from a PEM file as bytes.

func NoPty

func NoPty() Option

NoPty returns a functional option that sets PtyCallback to return false, denying PTY requests.

Example
package main

import (
	"github.com/gliderlabs/ssh"
)

func main() {
	ssh.ListenAndServe(":2222", nil, ssh.NoPty())
}
Output:

func PasswordAuth

func PasswordAuth(fn PasswordHandler) Option

PasswordAuth returns a functional option that sets PasswordHandler on the server.

Example
package main

import (
	"github.com/gliderlabs/ssh"
)

func main() {
	ssh.ListenAndServe(":2222", nil,
		ssh.PasswordAuth(func(user, pass string) bool {
			return pass == "secret"
		}),
	)
}
Output:

func PublicKeyAuth

func PublicKeyAuth(fn PublicKeyHandler) Option

PublicKeyAuth returns a functional option that sets PublicKeyHandler on the server.

Example
package main

import (
	"io/ioutil"

	"github.com/gliderlabs/ssh"
)

func main() {
	ssh.ListenAndServe(":2222", nil,
		ssh.PublicKeyAuth(func(user string, key ssh.PublicKey) bool {
			data, _ := ioutil.ReadFile("/path/to/allowed/key.pub")
			allowed, _, _, _, _ := ssh.ParseAuthorizedKey(data)
			return ssh.KeysEqual(key, allowed)
		}),
	)
}
Output:

type PasswordHandler

type PasswordHandler func(user, password string) bool

PasswordHandler is a callback for performing password authentication.

type Permissions

type Permissions struct {
	*gossh.Permissions
}

The Permissions type holds fine-grained permissions that are specific to a user or a specific authentication method for a user. Permissions, except for "source-address", must be enforced in the server application layer, after successful authentication. The Permissions are passed on in ServerConn so a server implementation can honor them.

type PermissionsCallback

type PermissionsCallback func(user string, permissions *Permissions) error

PermissionsCallback is a hook for setting up user permissions.

type Pty

type Pty struct {
	Window Window
}

Pty represents PTY configuration.

type PtyCallback

type PtyCallback func(user string, permissions *Permissions) bool

PtyCallback is a hook for allowing PTY sessions.

type PublicKey

type PublicKey interface {
	gossh.PublicKey
}

PublicKey is an abstraction of different types of public keys.

func ParseAuthorizedKey

func ParseAuthorizedKey(in []byte) (out PublicKey, comment string, options []string, rest []byte, err error)

ParseAuthorizedKey parses a public key from an authorized_keys file used in OpenSSH according to the sshd(8) manual page.

func ParsePublicKey

func ParsePublicKey(in []byte) (out PublicKey, err error)

ParsePublicKey parses an SSH public key formatted for use in the SSH wire protocol according to RFC 4253, section 6.6.

type PublicKeyHandler

type PublicKeyHandler func(user string, key PublicKey) bool

PublicKeyHandler is a callback for performing public key authentication.

type Server

type Server struct {
	Addr        string   // TCP address to listen on, ":22" if empty
	Handler     Handler  // handler to invoke, ssh.DefaultHandler if nil
	HostSigners []Signer // private keys for the host key, must have at least one
	Version     string   // server version to be sent before the initial handshake

	PasswordHandler     PasswordHandler     // password authentication handler
	PublicKeyHandler    PublicKeyHandler    // public key authentication handler
	PtyCallback         PtyCallback         // callback for allowing PTY sessions, allows all if nil
	PermissionsCallback PermissionsCallback // optional callback for setting up permissions
}

Server defines parameters for running an SSH server. The zero value for Server is a valid configuration. When both PasswordHandler and PublicKeyHandler are nil, no client authentication is performed.

func (*Server) AddHostKey

func (srv *Server) AddHostKey(key Signer)

AddHostKey adds a private key as a host key. If an existing host key exists with the same algorithm, it is overwritten. Each server config must have at least one host key.

func (*Server) Handle

func (srv *Server) Handle(fn Handler)

Handle sets the Handler for the server.

func (*Server) ListenAndServe

func (srv *Server) ListenAndServe() error

ListenAndServe listens on the TCP network address srv.Addr and then calls Serve to handle incoming connections. If srv.Addr is blank, ":22" is used. ListenAndServe always returns a non-nil error.

func (*Server) Serve

func (srv *Server) Serve(l net.Listener) error

Serve accepts incoming connections on the Listener l, creating a new connection goroutine for each. The connection goroutines read requests and then calls srv.Handler to handle sessions.

Serve always returns a non-nil error.

func (*Server) SetOption

func (srv *Server) SetOption(option Option) error

SetOption runs a functional option against the server.

type Session

type Session interface {
	gossh.Channel

	// User returns the username used when establishing the SSH connection.
	User() string

	// RemoteAddr returns the net.Addr of the client side of the connection.
	RemoteAddr() net.Addr

	// Environ returns a copy of strings representing the environment set by the
	// user for this session, in the form "key=value".
	Environ() []string

	// Exit sends an exit status and then closes the session.
	Exit(code int) error

	// Command returns a shell parsed slice of arguments that were provided by the
	// user. Shell parsing splits the command string according to POSIX shell rules,
	// which considers quoting not just whitespace.
	Command() []string

	// PublicKey returns the PublicKey used to authenticate. If a public key was not
	// used it will return nil.
	PublicKey() PublicKey

	// Pty returns PTY information, a channel of window size changes, and a boolean
	// of whether or not a PTY was accepted for this session.
	Pty() (Pty, <-chan Window, bool)
}

Session provides access to information about an SSH session and methods to read and write to the SSH channel with an embedded Channel interface from cypto/ssh.

When Command() returns an empty slice, the user requested a shell. Otherwise the user is performing an exec with those command arguments.

TODO: Signals

type Signal

type Signal string

Signal as in RFC 4254 Section 6.10.

const (
	SIGABRT Signal = "ABRT"
	SIGALRM Signal = "ALRM"
	SIGFPE  Signal = "FPE"
	SIGHUP  Signal = "HUP"
	SIGILL  Signal = "ILL"
	SIGINT  Signal = "INT"
	SIGKILL Signal = "KILL"
	SIGPIPE Signal = "PIPE"
	SIGQUIT Signal = "QUIT"
	SIGSEGV Signal = "SEGV"
	SIGTERM Signal = "TERM"
	SIGUSR1 Signal = "USR1"
	SIGUSR2 Signal = "USR2"
)

POSIX signals as listed in RFC 4254 Section 6.10.

type Signer

type Signer interface {
	gossh.Signer
}

A Signer can create signatures that verify against a public key.

type Window

type Window struct {
	Width  int
	Height int
}

Window represents the size of a PTY window.

Directories

Path Synopsis
_example

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL