You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

context.go 5.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. package ssh
  2. import (
  3. "context"
  4. "encoding/hex"
  5. "net"
  6. "sync"
  7. gossh "golang.org/x/crypto/ssh"
  8. )
  9. // contextKey is a value for use with context.WithValue. It's used as
  10. // a pointer so it fits in an interface{} without allocation.
  11. type contextKey struct {
  12. name string
  13. }
  14. var (
  15. // ContextKeyUser is a context key for use with Contexts in this package.
  16. // The associated value will be of type string.
  17. ContextKeyUser = &contextKey{"user"}
  18. // ContextKeySessionID is a context key for use with Contexts in this package.
  19. // The associated value will be of type string.
  20. ContextKeySessionID = &contextKey{"session-id"}
  21. // ContextKeyPermissions is a context key for use with Contexts in this package.
  22. // The associated value will be of type *Permissions.
  23. ContextKeyPermissions = &contextKey{"permissions"}
  24. // ContextKeyClientVersion is a context key for use with Contexts in this package.
  25. // The associated value will be of type string.
  26. ContextKeyClientVersion = &contextKey{"client-version"}
  27. // ContextKeyServerVersion is a context key for use with Contexts in this package.
  28. // The associated value will be of type string.
  29. ContextKeyServerVersion = &contextKey{"server-version"}
  30. // ContextKeyLocalAddr is a context key for use with Contexts in this package.
  31. // The associated value will be of type net.Addr.
  32. ContextKeyLocalAddr = &contextKey{"local-addr"}
  33. // ContextKeyRemoteAddr is a context key for use with Contexts in this package.
  34. // The associated value will be of type net.Addr.
  35. ContextKeyRemoteAddr = &contextKey{"remote-addr"}
  36. // ContextKeyServer is a context key for use with Contexts in this package.
  37. // The associated value will be of type *Server.
  38. ContextKeyServer = &contextKey{"ssh-server"}
  39. // ContextKeyConn is a context key for use with Contexts in this package.
  40. // The associated value will be of type gossh.ServerConn.
  41. ContextKeyConn = &contextKey{"ssh-conn"}
  42. // ContextKeyPublicKey is a context key for use with Contexts in this package.
  43. // The associated value will be of type PublicKey.
  44. ContextKeyPublicKey = &contextKey{"public-key"}
  45. )
  46. // Context is a package specific context interface. It exposes connection
  47. // metadata and allows new values to be easily written to it. It's used in
  48. // authentication handlers and callbacks, and its underlying context.Context is
  49. // exposed on Session in the session Handler. A connection-scoped lock is also
  50. // embedded in the context to make it easier to limit operations per-connection.
  51. type Context interface {
  52. context.Context
  53. sync.Locker
  54. // User returns the username used when establishing the SSH connection.
  55. User() string
  56. // SessionID returns the session hash.
  57. SessionID() string
  58. // ClientVersion returns the version reported by the client.
  59. ClientVersion() string
  60. // ServerVersion returns the version reported by the server.
  61. ServerVersion() string
  62. // RemoteAddr returns the remote address for this connection.
  63. RemoteAddr() net.Addr
  64. // LocalAddr returns the local address for this connection.
  65. LocalAddr() net.Addr
  66. // Permissions returns the Permissions object used for this connection.
  67. Permissions() *Permissions
  68. // SetValue allows you to easily write new values into the underlying context.
  69. SetValue(key, value interface{})
  70. }
  71. type sshContext struct {
  72. context.Context
  73. *sync.Mutex
  74. }
  75. func newContext(srv *Server) (*sshContext, context.CancelFunc) {
  76. innerCtx, cancel := context.WithCancel(context.Background())
  77. ctx := &sshContext{innerCtx, &sync.Mutex{}}
  78. ctx.SetValue(ContextKeyServer, srv)
  79. perms := &Permissions{&gossh.Permissions{}}
  80. ctx.SetValue(ContextKeyPermissions, perms)
  81. return ctx, cancel
  82. }
  83. // this is separate from newContext because we will get ConnMetadata
  84. // at different points so it needs to be applied separately
  85. func applyConnMetadata(ctx Context, conn gossh.ConnMetadata) {
  86. if ctx.Value(ContextKeySessionID) != nil {
  87. return
  88. }
  89. ctx.SetValue(ContextKeySessionID, hex.EncodeToString(conn.SessionID()))
  90. ctx.SetValue(ContextKeyClientVersion, string(conn.ClientVersion()))
  91. ctx.SetValue(ContextKeyServerVersion, string(conn.ServerVersion()))
  92. ctx.SetValue(ContextKeyUser, conn.User())
  93. ctx.SetValue(ContextKeyLocalAddr, conn.LocalAddr())
  94. ctx.SetValue(ContextKeyRemoteAddr, conn.RemoteAddr())
  95. }
  96. func (ctx *sshContext) SetValue(key, value interface{}) {
  97. ctx.Context = context.WithValue(ctx.Context, key, value)
  98. }
  99. func (ctx *sshContext) User() string {
  100. return ctx.Value(ContextKeyUser).(string)
  101. }
  102. func (ctx *sshContext) SessionID() string {
  103. return ctx.Value(ContextKeySessionID).(string)
  104. }
  105. func (ctx *sshContext) ClientVersion() string {
  106. return ctx.Value(ContextKeyClientVersion).(string)
  107. }
  108. func (ctx *sshContext) ServerVersion() string {
  109. return ctx.Value(ContextKeyServerVersion).(string)
  110. }
  111. func (ctx *sshContext) RemoteAddr() net.Addr {
  112. if addr, ok := ctx.Value(ContextKeyRemoteAddr).(net.Addr); ok {
  113. return addr
  114. }
  115. return nil
  116. }
  117. func (ctx *sshContext) LocalAddr() net.Addr {
  118. return ctx.Value(ContextKeyLocalAddr).(net.Addr)
  119. }
  120. func (ctx *sshContext) Permissions() *Permissions {
  121. return ctx.Value(ContextKeyPermissions).(*Permissions)
  122. }