ssh.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. package ssh
  2. import (
  3. "crypto/subtle"
  4. "net"
  5. gossh "golang.org/x/crypto/ssh"
  6. )
  7. type Signal string
  8. // POSIX signals as listed in RFC 4254 Section 6.10.
  9. const (
  10. SIGABRT Signal = "ABRT"
  11. SIGALRM Signal = "ALRM"
  12. SIGFPE Signal = "FPE"
  13. SIGHUP Signal = "HUP"
  14. SIGILL Signal = "ILL"
  15. SIGINT Signal = "INT"
  16. SIGKILL Signal = "KILL"
  17. SIGPIPE Signal = "PIPE"
  18. SIGQUIT Signal = "QUIT"
  19. SIGSEGV Signal = "SEGV"
  20. SIGTERM Signal = "TERM"
  21. SIGUSR1 Signal = "USR1"
  22. SIGUSR2 Signal = "USR2"
  23. )
  24. // DefaultHandler is the default Handler used by Serve.
  25. var DefaultHandler Handler
  26. // Option is a functional option handler for Server.
  27. type Option func(*Server) error
  28. // Handler is a callback for handling established SSH sessions.
  29. type Handler func(Session)
  30. // PublicKeyHandler is a callback for performing public key authentication.
  31. type PublicKeyHandler func(ctx Context, key PublicKey) error
  32. type NoClientAuthHandler func(ctx Context) error
  33. type BannerHandler func(ctx Context) string
  34. // PasswordHandler is a callback for performing password authentication.
  35. type PasswordHandler func(ctx Context, password string) bool
  36. // KeyboardInteractiveHandler is a callback for performing keyboard-interactive authentication.
  37. type KeyboardInteractiveHandler func(ctx Context, challenger gossh.KeyboardInteractiveChallenge) bool
  38. // PtyCallback is a hook for allowing PTY sessions.
  39. type PtyCallback func(ctx Context, pty Pty) bool
  40. // SessionRequestCallback is a callback for allowing or denying SSH sessions.
  41. type SessionRequestCallback func(sess Session, requestType string) bool
  42. // ConnCallback is a hook for new connections before handling.
  43. // It allows wrapping for timeouts and limiting by returning
  44. // the net.Conn that will be used as the underlying connection.
  45. type ConnCallback func(ctx Context, conn net.Conn) net.Conn
  46. // LocalPortForwardingCallback is a hook for allowing port forwarding
  47. type LocalPortForwardingCallback func(ctx Context, destinationHost string, destinationPort uint32) bool
  48. // ReversePortForwardingCallback is a hook for allowing reverse port forwarding
  49. type ReversePortForwardingCallback func(ctx Context, bindHost string, bindPort uint32) bool
  50. // ServerConfigCallback is a hook for creating custom default server configs
  51. type ServerConfigCallback func(ctx Context) *gossh.ServerConfig
  52. // ConnectionFailedCallback is a hook for reporting failed connections
  53. // Please note: the net.Conn is likely to be closed at this point
  54. type ConnectionFailedCallback func(conn net.Conn, err error)
  55. // Window represents the size of a PTY window.
  56. //
  57. // See https://datatracker.ietf.org/doc/html/rfc4254#section-6.2
  58. //
  59. // Zero dimension parameters MUST be ignored. The character/row dimensions
  60. // override the pixel dimensions (when nonzero). Pixel dimensions refer
  61. // to the drawable area of the window.
  62. type Window struct {
  63. // Width is the number of columns.
  64. // It overrides WidthPixels.
  65. Width int
  66. // Height is the number of rows.
  67. // It overrides HeightPixels.
  68. Height int
  69. // WidthPixels is the drawable width of the window, in pixels.
  70. WidthPixels int
  71. // HeightPixels is the drawable height of the window, in pixels.
  72. HeightPixels int
  73. }
  74. // Pty represents a PTY request and configuration.
  75. type Pty struct {
  76. // Term is the TERM environment variable value.
  77. Term string
  78. // Window is the Window sent as part of the pty-req.
  79. Window Window
  80. // Modes represent a mapping of Terminal Mode opcode to value as it was
  81. // requested by the client as part of the pty-req. These are outlined as
  82. // part of https://datatracker.ietf.org/doc/html/rfc4254#section-8.
  83. //
  84. // The opcodes are defined as constants in golang.org/x/crypto/ssh (VINTR,VQUIT,etc.).
  85. // Boolean opcodes have values 0 or 1.
  86. Modes gossh.TerminalModes
  87. }
  88. // Serve accepts incoming SSH connections on the listener l, creating a new
  89. // connection goroutine for each. The connection goroutines read requests and
  90. // then calls handler to handle sessions. Handler is typically nil, in which
  91. // case the DefaultHandler is used.
  92. func Serve(l net.Listener, handler Handler, options ...Option) error {
  93. srv := &Server{Handler: handler}
  94. for _, option := range options {
  95. if err := srv.SetOption(option); err != nil {
  96. return err
  97. }
  98. }
  99. return srv.Serve(l)
  100. }
  101. // ListenAndServe listens on the TCP network address addr and then calls Serve
  102. // with handler to handle sessions on incoming connections. Handler is typically
  103. // nil, in which case the DefaultHandler is used.
  104. func ListenAndServe(addr string, handler Handler, options ...Option) error {
  105. srv := &Server{Addr: addr, Handler: handler}
  106. for _, option := range options {
  107. if err := srv.SetOption(option); err != nil {
  108. return err
  109. }
  110. }
  111. return srv.ListenAndServe()
  112. }
  113. // Handle registers the handler as the DefaultHandler.
  114. func Handle(handler Handler) {
  115. DefaultHandler = handler
  116. }
  117. // KeysEqual is constant time compare of the keys to avoid timing attacks.
  118. func KeysEqual(ak, bk PublicKey) bool {
  119. //avoid panic if one of the keys is nil, return false instead
  120. if ak == nil || bk == nil {
  121. return false
  122. }
  123. a := ak.Marshal()
  124. b := bk.Marshal()
  125. return (len(a) == len(b) && subtle.ConstantTimeCompare(a, b) == 1)
  126. }