123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155 |
- package ssh
-
- import (
- "context"
- "encoding/hex"
- "net"
- "sync"
-
- gossh "golang.org/x/crypto/ssh"
- )
-
- // contextKey is a value for use with context.WithValue. It's used as
- // a pointer so it fits in an interface{} without allocation.
- type contextKey struct {
- name string
- }
-
- var (
- // ContextKeyUser is a context key for use with Contexts in this package.
- // The associated value will be of type string.
- ContextKeyUser = &contextKey{"user"}
-
- // ContextKeySessionID is a context key for use with Contexts in this package.
- // The associated value will be of type string.
- ContextKeySessionID = &contextKey{"session-id"}
-
- // ContextKeyPermissions is a context key for use with Contexts in this package.
- // The associated value will be of type *Permissions.
- ContextKeyPermissions = &contextKey{"permissions"}
-
- // ContextKeyClientVersion is a context key for use with Contexts in this package.
- // The associated value will be of type string.
- ContextKeyClientVersion = &contextKey{"client-version"}
-
- // ContextKeyServerVersion is a context key for use with Contexts in this package.
- // The associated value will be of type string.
- ContextKeyServerVersion = &contextKey{"server-version"}
-
- // ContextKeyLocalAddr is a context key for use with Contexts in this package.
- // The associated value will be of type net.Addr.
- ContextKeyLocalAddr = &contextKey{"local-addr"}
-
- // ContextKeyRemoteAddr is a context key for use with Contexts in this package.
- // The associated value will be of type net.Addr.
- ContextKeyRemoteAddr = &contextKey{"remote-addr"}
-
- // ContextKeyServer is a context key for use with Contexts in this package.
- // The associated value will be of type *Server.
- ContextKeyServer = &contextKey{"ssh-server"}
-
- // ContextKeyConn is a context key for use with Contexts in this package.
- // The associated value will be of type gossh.ServerConn.
- ContextKeyConn = &contextKey{"ssh-conn"}
-
- // ContextKeyPublicKey is a context key for use with Contexts in this package.
- // The associated value will be of type PublicKey.
- ContextKeyPublicKey = &contextKey{"public-key"}
- )
-
- // Context is a package specific context interface. It exposes connection
- // metadata and allows new values to be easily written to it. It's used in
- // authentication handlers and callbacks, and its underlying context.Context is
- // exposed on Session in the session Handler. A connection-scoped lock is also
- // embedded in the context to make it easier to limit operations per-connection.
- type Context interface {
- context.Context
- sync.Locker
-
- // User returns the username used when establishing the SSH connection.
- User() string
-
- // SessionID returns the session hash.
- SessionID() string
-
- // ClientVersion returns the version reported by the client.
- ClientVersion() string
-
- // ServerVersion returns the version reported by the server.
- ServerVersion() string
-
- // RemoteAddr returns the remote address for this connection.
- RemoteAddr() net.Addr
-
- // LocalAddr returns the local address for this connection.
- LocalAddr() net.Addr
-
- // Permissions returns the Permissions object used for this connection.
- Permissions() *Permissions
-
- // SetValue allows you to easily write new values into the underlying context.
- SetValue(key, value interface{})
- }
-
- type sshContext struct {
- context.Context
- *sync.Mutex
- }
-
- func newContext(srv *Server) (*sshContext, context.CancelFunc) {
- innerCtx, cancel := context.WithCancel(context.Background())
- ctx := &sshContext{innerCtx, &sync.Mutex{}}
- ctx.SetValue(ContextKeyServer, srv)
- perms := &Permissions{&gossh.Permissions{}}
- ctx.SetValue(ContextKeyPermissions, perms)
- return ctx, cancel
- }
-
- // this is separate from newContext because we will get ConnMetadata
- // at different points so it needs to be applied separately
- func applyConnMetadata(ctx Context, conn gossh.ConnMetadata) {
- if ctx.Value(ContextKeySessionID) != nil {
- return
- }
- ctx.SetValue(ContextKeySessionID, hex.EncodeToString(conn.SessionID()))
- ctx.SetValue(ContextKeyClientVersion, string(conn.ClientVersion()))
- ctx.SetValue(ContextKeyServerVersion, string(conn.ServerVersion()))
- ctx.SetValue(ContextKeyUser, conn.User())
- ctx.SetValue(ContextKeyLocalAddr, conn.LocalAddr())
- ctx.SetValue(ContextKeyRemoteAddr, conn.RemoteAddr())
- }
-
- func (ctx *sshContext) SetValue(key, value interface{}) {
- ctx.Context = context.WithValue(ctx.Context, key, value)
- }
-
- func (ctx *sshContext) User() string {
- return ctx.Value(ContextKeyUser).(string)
- }
-
- func (ctx *sshContext) SessionID() string {
- return ctx.Value(ContextKeySessionID).(string)
- }
-
- func (ctx *sshContext) ClientVersion() string {
- return ctx.Value(ContextKeyClientVersion).(string)
- }
-
- func (ctx *sshContext) ServerVersion() string {
- return ctx.Value(ContextKeyServerVersion).(string)
- }
-
- func (ctx *sshContext) RemoteAddr() net.Addr {
- if addr, ok := ctx.Value(ContextKeyRemoteAddr).(net.Addr); ok {
- return addr
- }
- return nil
- }
-
- func (ctx *sshContext) LocalAddr() net.Addr {
- return ctx.Value(ContextKeyLocalAddr).(net.Addr)
- }
-
- func (ctx *sshContext) Permissions() *Permissions {
- return ctx.Value(ContextKeyPermissions).(*Permissions)
- }
|