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