Платформа ЦРНП "Мирокод" для разработки проектов
https://git.mirocod.ru
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.
152 lines
4.9 KiB
152 lines
4.9 KiB
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) |
|
}
|
|
|