153 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			153 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			Go
		
	
	
	
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 {
 | 
						|
	return ctx.Value(ContextKeyRemoteAddr).(net.Addr)
 | 
						|
}
 | 
						|
 | 
						|
func (ctx *sshContext) LocalAddr() net.Addr {
 | 
						|
	return ctx.Value(ContextKeyLocalAddr).(net.Addr)
 | 
						|
}
 | 
						|
 | 
						|
func (ctx *sshContext) Permissions() *Permissions {
 | 
						|
	return ctx.Value(ContextKeyPermissions).(*Permissions)
 | 
						|
}
 |