Skip to content

Commit 79230d5

Browse files
authored
Merge branch 'gliderlabs:master' into master
2 parents 81194fc + d137aad commit 79230d5

File tree

12 files changed

+93
-34
lines changed

12 files changed

+93
-34
lines changed

_examples/ssh-sftpserver/sftp.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package main
33
import (
44
"fmt"
55
"io"
6-
"io/ioutil"
76
"log"
87

98
"github.com/gliderlabs/ssh"
@@ -12,7 +11,7 @@ import (
1211

1312
// SftpHandler handler for SFTP subsystem
1413
func SftpHandler(sess ssh.Session) {
15-
debugStream := ioutil.Discard
14+
debugStream := io.Discard
1615
serverOptions := []sftp.ServerOption{
1716
sftp.WithDebug(debugStream),
1817
}

agent.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ package ssh
22

33
import (
44
"io"
5-
"io/ioutil"
65
"net"
6+
"os"
77
"path"
88
"sync"
99

@@ -36,7 +36,7 @@ func AgentRequested(sess Session) bool {
3636
// NewAgentListener sets up a temporary Unix socket that can be communicated
3737
// to the session environment and used for forwarding connections.
3838
func NewAgentListener() (net.Listener, error) {
39-
dir, err := ioutil.TempDir("", agentTempDir)
39+
dir, err := os.MkdirTemp("", agentTempDir)
4040
if err != nil {
4141
return nil, err
4242
}

circle.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ jobs:
99
- run: go get
1010
- run: go test -v -race
1111

12-
build-go-1.13:
12+
build-go-1.20:
1313
docker:
14-
- image: golang:1.13
14+
- image: golang:1.20
1515
working_directory: /go/src/github.com/gliderlabs/ssh
1616
steps:
1717
- checkout
@@ -23,4 +23,4 @@ workflows:
2323
build:
2424
jobs:
2525
- build-go-latest
26-
- build-go-1.13
26+
- build-go-1.20

context.go

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,11 +94,14 @@ type Context interface {
9494
type sshContext struct {
9595
context.Context
9696
*sync.Mutex
97+
98+
values map[interface{}]interface{}
99+
valuesMu sync.Mutex
97100
}
98101

99102
func newContext(srv *Server) (*sshContext, context.CancelFunc) {
100103
innerCtx, cancel := context.WithCancel(context.Background())
101-
ctx := &sshContext{innerCtx, &sync.Mutex{}}
104+
ctx := &sshContext{Context: innerCtx, Mutex: &sync.Mutex{}, values: make(map[interface{}]interface{})}
102105
ctx.SetValue(ContextKeyServer, srv)
103106
perms := &Permissions{&gossh.Permissions{}}
104107
ctx.SetValue(ContextKeyPermissions, perms)
@@ -119,8 +122,19 @@ func applyConnMetadata(ctx Context, conn gossh.ConnMetadata) {
119122
ctx.SetValue(ContextKeyRemoteAddr, conn.RemoteAddr())
120123
}
121124

125+
func (ctx *sshContext) Value(key interface{}) interface{} {
126+
ctx.valuesMu.Lock()
127+
defer ctx.valuesMu.Unlock()
128+
if v, ok := ctx.values[key]; ok {
129+
return v
130+
}
131+
return ctx.Context.Value(key)
132+
}
133+
122134
func (ctx *sshContext) SetValue(key, value interface{}) {
123-
ctx.Context = context.WithValue(ctx.Context, key, value)
135+
ctx.valuesMu.Lock()
136+
defer ctx.valuesMu.Unlock()
137+
ctx.values[key] = value
124138
}
125139

126140
func (ctx *sshContext) User() string {

context_test.go

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package ssh
22

3-
import "testing"
3+
import (
4+
"testing"
5+
"time"
6+
)
47

58
func TestSetPermissions(t *testing.T) {
69
t.Parallel()
@@ -45,3 +48,38 @@ func TestSetValue(t *testing.T) {
4548
t.Fatal(err)
4649
}
4750
}
51+
52+
func TestSetValueConcurrency(t *testing.T) {
53+
ctx, cancel := newContext(nil)
54+
defer cancel()
55+
56+
go func() {
57+
for { // use a loop to access context.Context functions to make sure they are thread-safe with SetValue
58+
_, _ = ctx.Deadline()
59+
_ = ctx.Err()
60+
_ = ctx.Value("foo")
61+
select {
62+
case <-ctx.Done():
63+
break
64+
default:
65+
}
66+
}
67+
}()
68+
ctx.SetValue("bar", -1) // a context value which never changes
69+
now := time.Now()
70+
var cnt int64
71+
go func() {
72+
for time.Since(now) < 100*time.Millisecond {
73+
cnt++
74+
ctx.SetValue("foo", cnt) // a context value which changes a lot
75+
}
76+
cancel()
77+
}()
78+
<-ctx.Done()
79+
if ctx.Value("foo") != cnt {
80+
t.Fatal("context.Value(foo) doesn't match latest SetValue")
81+
}
82+
if ctx.Value("bar") != -1 {
83+
t.Fatal("context.Value(bar) doesn't match latest SetValue")
84+
}
85+
}

example_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package ssh_test
22

33
import (
44
"io"
5-
"io/ioutil"
5+
"os"
66

77
"github.com/gliderlabs/ssh"
88
)
@@ -28,7 +28,7 @@ func ExampleNoPty() {
2828
func ExamplePublicKeyAuth() {
2929
ssh.ListenAndServe(":2222", nil,
3030
ssh.PublicKeyAuth(func(ctx ssh.Context, key ssh.PublicKey) bool {
31-
data, _ := ioutil.ReadFile("/path/to/allowed/key.pub")
31+
data, _ := os.ReadFile("/path/to/allowed/key.pub")
3232
allowed, _, _, _, _ := ssh.ParseAuthorizedKey(data)
3333
return ssh.KeysEqual(key, allowed)
3434
}),

go.mod

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
module github.com/gliderlabs/ssh
22

3-
go 1.12
3+
go 1.20
44

55
require (
66
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be
7-
golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d
8-
golang.org/x/term v0.5.0 // indirect
7+
golang.org/x/crypto v0.31.0
98
)
9+
10+
require golang.org/x/sys v0.28.0 // indirect

go.sum

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,7 @@
11
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
22
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
3-
golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d h1:3qF+Z8Hkrw9sOhrFHti9TlB1Hkac1x+DNRkv0XQiFjo=
4-
golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
5-
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
6-
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
7-
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
8-
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
9-
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
10-
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
11-
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
12-
golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY=
13-
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
14-
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
15-
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
3+
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
4+
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
5+
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
6+
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
7+
golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=

options.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package ssh
22

33
import (
4-
"io/ioutil"
4+
"os"
55

66
gossh "golang.org/x/crypto/ssh"
77
)
@@ -26,7 +26,7 @@ func PublicKeyAuth(fn PublicKeyHandler) Option {
2626
// from a PEM file at filepath.
2727
func HostKeyFile(filepath string) Option {
2828
return func(srv *Server) error {
29-
pemBytes, err := ioutil.ReadFile(filepath)
29+
pemBytes, err := os.ReadFile(filepath)
3030
if err != nil {
3131
return err
3232
}

server.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@ type Server struct {
3737
Handler Handler // handler to invoke, ssh.DefaultHandler if nil
3838
HostSigners []Signer // private keys for the host key, must have at least one
3939
Version string // server version to be sent before the initial handshake
40+
Banner string // server banner
4041

42+
BannerHandler BannerHandler // server banner handler, overrides Banner
4143
KeyboardInteractiveHandler KeyboardInteractiveHandler // keyboard-interactive authentication handler
4244
PasswordHandler PasswordHandler // password authentication handler
4345
PublicKeyHandler PublicKeyHandler // public key authentication handler
@@ -132,6 +134,17 @@ func (srv *Server) config(ctx Context) *gossh.ServerConfig {
132134
if srv.Version != "" {
133135
config.ServerVersion = "SSH-2.0-" + srv.Version
134136
}
137+
if srv.Banner != "" {
138+
config.BannerCallback = func(_ gossh.ConnMetadata) string {
139+
return srv.Banner
140+
}
141+
}
142+
if srv.BannerHandler != nil {
143+
config.BannerCallback = func(conn gossh.ConnMetadata) string {
144+
applyConnMetadata(ctx, conn)
145+
return srv.BannerHandler(ctx)
146+
}
147+
}
135148
if srv.PasswordHandler != nil {
136149
config.PasswordCallback = func(conn gossh.ConnMetadata, password []byte) (*gossh.Permissions, error) {
137150
applyConnMetadata(ctx, conn)

ssh.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ type Option func(*Server) error
3535
// Handler is a callback for handling established SSH sessions.
3636
type Handler func(Session)
3737

38+
// BannerHandler is a callback for displaying the server banner.
39+
type BannerHandler func(ctx Context) string
40+
3841
// PublicKeyHandler is a callback for performing public key authentication.
3942
type PublicKeyHandler func(ctx Context, key PublicKey) bool
4043

@@ -115,8 +118,7 @@ func Handle(handler Handler) {
115118

116119
// KeysEqual is constant time compare of the keys to avoid timing attacks.
117120
func KeysEqual(ak, bk PublicKey) bool {
118-
119-
//avoid panic if one of the keys is nil, return false instead
121+
// avoid panic if one of the keys is nil, return false instead
120122
if ak == nil || bk == nil {
121123
return false
122124
}

tcpip_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package ssh
22

33
import (
44
"bytes"
5-
"io/ioutil"
5+
"io"
66
"net"
77
"strconv"
88
"strings"
@@ -58,7 +58,7 @@ func TestLocalPortForwardingWorks(t *testing.T) {
5858
if err != nil {
5959
t.Fatalf("Error connecting to %v: %v", l.Addr().String(), err)
6060
}
61-
result, err := ioutil.ReadAll(conn)
61+
result, err := io.ReadAll(conn)
6262
if err != nil {
6363
t.Fatal(err)
6464
}

0 commit comments

Comments
 (0)