mirror of
				https://github.com/tailscale/tailscale.git
				synced 2025-10-31 00:01:40 +01:00 
			
		
		
		
	The upstream crypto package now supports sending banners at any time during authentication, so the Tailscale fork of crypto/ssh is no longer necessary. github.com/tailscale/golang-x-crypto is still needed for some custom ACME autocert functionality. tempfork/gliderlabs is still necessary because of a few other customizations, mostly related to TTY handling. Originally implemented in 46fd4e58a27495263336b86ee961ee28d8c332b7, which was reverted in b60f6b849af1fae1cf343be98f7fb1714c9ea165 to keep the change out of v1.80. Updates #8593 Signed-off-by: Percy Wegmann <percy@tailscale.com>
		
			
				
	
	
		
			157 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			157 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package ssh
 | |
| 
 | |
| import (
 | |
| 	"crypto/subtle"
 | |
| 	"net"
 | |
| 
 | |
| 	gossh "golang.org/x/crypto/ssh"
 | |
| )
 | |
| 
 | |
| type Signal string
 | |
| 
 | |
| // POSIX signals as listed 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"
 | |
| )
 | |
| 
 | |
| // DefaultHandler is the default Handler used by Serve.
 | |
| var DefaultHandler Handler
 | |
| 
 | |
| // Option is a functional option handler for Server.
 | |
| type Option func(*Server) error
 | |
| 
 | |
| // Handler is a callback for handling established SSH sessions.
 | |
| type Handler func(Session)
 | |
| 
 | |
| // PublicKeyHandler is a callback for performing public key authentication.
 | |
| type PublicKeyHandler func(ctx Context, key PublicKey) error
 | |
| 
 | |
| type NoClientAuthHandler func(ctx Context) error
 | |
| 
 | |
| type BannerHandler func(ctx Context) string
 | |
| 
 | |
| // PasswordHandler is a callback for performing password authentication.
 | |
| type PasswordHandler func(ctx Context, password string) bool
 | |
| 
 | |
| // KeyboardInteractiveHandler is a callback for performing keyboard-interactive authentication.
 | |
| type KeyboardInteractiveHandler func(ctx Context, challenger gossh.KeyboardInteractiveChallenge) bool
 | |
| 
 | |
| // PtyCallback is a hook for allowing PTY sessions.
 | |
| type PtyCallback func(ctx Context, pty Pty) bool
 | |
| 
 | |
| // SessionRequestCallback is a callback for allowing or denying SSH sessions.
 | |
| type SessionRequestCallback func(sess Session, requestType string) bool
 | |
| 
 | |
| // ConnCallback is a hook for new connections before handling.
 | |
| // It allows wrapping for timeouts and limiting by returning
 | |
| // the net.Conn that will be used as the underlying connection.
 | |
| type ConnCallback func(ctx Context, conn net.Conn) net.Conn
 | |
| 
 | |
| // LocalPortForwardingCallback is a hook for allowing port forwarding
 | |
| type LocalPortForwardingCallback func(ctx Context, destinationHost string, destinationPort uint32) bool
 | |
| 
 | |
| // ReversePortForwardingCallback is a hook for allowing reverse port forwarding
 | |
| type ReversePortForwardingCallback func(ctx Context, bindHost string, bindPort uint32) bool
 | |
| 
 | |
| // ServerConfigCallback is a hook for creating custom default server configs
 | |
| type ServerConfigCallback func(ctx Context) *gossh.ServerConfig
 | |
| 
 | |
| // ConnectionFailedCallback is a hook for reporting failed connections
 | |
| // Please note: the net.Conn is likely to be closed at this point
 | |
| type ConnectionFailedCallback func(conn net.Conn, err error)
 | |
| 
 | |
| // Window represents the size of a PTY window.
 | |
| //
 | |
| // See https://datatracker.ietf.org/doc/html/rfc4254#section-6.2
 | |
| //
 | |
| // Zero dimension parameters MUST be ignored. The character/row dimensions
 | |
| // override the pixel dimensions (when nonzero).  Pixel dimensions refer
 | |
| // to the drawable area of the window.
 | |
| type Window struct {
 | |
| 	// Width is the number of columns.
 | |
| 	// It overrides WidthPixels.
 | |
| 	Width int
 | |
| 	// Height is the number of rows.
 | |
| 	// It overrides HeightPixels.
 | |
| 	Height int
 | |
| 
 | |
| 	// WidthPixels is the drawable width of the window, in pixels.
 | |
| 	WidthPixels int
 | |
| 	// HeightPixels is the drawable height of the window, in pixels.
 | |
| 	HeightPixels int
 | |
| }
 | |
| 
 | |
| // Pty represents a PTY request and configuration.
 | |
| type Pty struct {
 | |
| 	// Term is the TERM environment variable value.
 | |
| 	Term string
 | |
| 
 | |
| 	// Window is the Window sent as part of the pty-req.
 | |
| 	Window Window
 | |
| 
 | |
| 	// Modes represent a mapping of Terminal Mode opcode to value as it was
 | |
| 	// requested by the client as part of the pty-req. These are outlined as
 | |
| 	// part of https://datatracker.ietf.org/doc/html/rfc4254#section-8.
 | |
| 	//
 | |
| 	// The opcodes are defined as constants in golang.org/x/crypto/ssh (VINTR,VQUIT,etc.).
 | |
| 	// Boolean opcodes have values 0 or 1.
 | |
| 	Modes gossh.TerminalModes
 | |
| }
 | |
| 
 | |
| // 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.
 | |
| func Serve(l net.Listener, handler Handler, options ...Option) error {
 | |
| 	srv := &Server{Handler: handler}
 | |
| 	for _, option := range options {
 | |
| 		if err := srv.SetOption(option); err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 	}
 | |
| 	return srv.Serve(l)
 | |
| }
 | |
| 
 | |
| // 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.
 | |
| func ListenAndServe(addr string, handler Handler, options ...Option) error {
 | |
| 	srv := &Server{Addr: addr, Handler: handler}
 | |
| 	for _, option := range options {
 | |
| 		if err := srv.SetOption(option); err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 	}
 | |
| 	return srv.ListenAndServe()
 | |
| }
 | |
| 
 | |
| // Handle registers the handler as the DefaultHandler.
 | |
| func Handle(handler Handler) {
 | |
| 	DefaultHandler = handler
 | |
| }
 | |
| 
 | |
| // KeysEqual is constant time compare of the keys to avoid timing attacks.
 | |
| func KeysEqual(ak, bk PublicKey) bool {
 | |
| 
 | |
| 	//avoid panic if one of the keys is nil, return false instead
 | |
| 	if ak == nil || bk == nil {
 | |
| 		return false
 | |
| 	}
 | |
| 
 | |
| 	a := ak.Marshal()
 | |
| 	b := bk.Marshal()
 | |
| 	return (len(a) == len(b) && subtle.ConstantTimeCompare(a, b) == 1)
 | |
| }
 |