Skip to content

Commit e5ece14

Browse files
belakprogrium
authored andcommitted
Add SessionPolicyCallback (#80)
* Add SessionPolicyCallback Closes #7 * Update docs related to the embedded sync.Locker in the Context * Fix mutex in context
1 parent 4b72c66 commit e5ece14

File tree

4 files changed

+43
-22
lines changed

4 files changed

+43
-22
lines changed

context.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"encoding/hex"
66
"net"
7+
"sync"
78

89
gossh "golang.org/x/crypto/ssh"
910
)
@@ -59,9 +60,11 @@ var (
5960
// Context is a package specific context interface. It exposes connection
6061
// metadata and allows new values to be easily written to it. It's used in
6162
// authentication handlers and callbacks, and its underlying context.Context is
62-
// exposed on Session in the session Handler.
63+
// exposed on Session in the session Handler. A connection-scoped lock is also
64+
// embedded in the context to make it easier to limit operations per-connection.
6365
type Context interface {
6466
context.Context
67+
sync.Locker
6568

6669
// User returns the username used when establishing the SSH connection.
6770
User() string
@@ -90,11 +93,12 @@ type Context interface {
9093

9194
type sshContext struct {
9295
context.Context
96+
*sync.Mutex
9397
}
9498

9599
func newContext(srv *Server) (*sshContext, context.CancelFunc) {
96100
innerCtx, cancel := context.WithCancel(context.Background())
97-
ctx := &sshContext{innerCtx}
101+
ctx := &sshContext{innerCtx, &sync.Mutex{}}
98102
ctx.SetValue(ContextKeyServer, srv)
99103
perms := &Permissions{&gossh.Permissions{}}
100104
ctx.SetValue(ContextKeyPermissions, perms)

server.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ type Server struct {
3232
LocalPortForwardingCallback LocalPortForwardingCallback // callback for allowing local port forwarding, denies all if nil
3333
ReversePortForwardingCallback ReversePortForwardingCallback // callback for allowing reverse port forwarding, denies all if nil
3434
DefaultServerConfigCallback DefaultServerConfigCallback // callback for configuring detailed SSH options
35+
SessionRequestCallback SessionRequestCallback // callback for allowing or denying SSH sessions
3536

3637
IdleTimeout time.Duration // connection timeout when no activity, none if empty
3738
MaxTimeout time.Duration // absolute connection timeout, none if empty

session.go

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -84,30 +84,32 @@ func sessionHandler(srv *Server, conn *gossh.ServerConn, newChan gossh.NewChanne
8484
return
8585
}
8686
sess := &session{
87-
Channel: ch,
88-
conn: conn,
89-
handler: srv.Handler,
90-
ptyCb: srv.PtyCallback,
91-
ctx: ctx,
87+
Channel: ch,
88+
conn: conn,
89+
handler: srv.Handler,
90+
ptyCb: srv.PtyCallback,
91+
sessReqCb: srv.SessionRequestCallback,
92+
ctx: ctx,
9293
}
9394
sess.handleRequests(reqs)
9495
}
9596

9697
type session struct {
9798
sync.Mutex
9899
gossh.Channel
99-
conn *gossh.ServerConn
100-
handler Handler
101-
handled bool
102-
exited bool
103-
pty *Pty
104-
winch chan Window
105-
env []string
106-
ptyCb PtyCallback
107-
cmd []string
108-
ctx Context
109-
sigCh chan<- Signal
110-
sigBuf []Signal
100+
conn *gossh.ServerConn
101+
handler Handler
102+
handled bool
103+
exited bool
104+
pty *Pty
105+
winch chan Window
106+
env []string
107+
ptyCb PtyCallback
108+
sessReqCb SessionRequestCallback
109+
cmd []string
110+
ctx Context
111+
sigCh chan<- Signal
112+
sigBuf []Signal
111113
}
112114

113115
func (sess *session) Write(p []byte) (n int, err error) {
@@ -209,12 +211,22 @@ func (sess *session) handleRequests(reqs <-chan *gossh.Request) {
209211
req.Reply(false, nil)
210212
continue
211213
}
212-
sess.handled = true
213-
req.Reply(true, nil)
214214

215215
var payload = struct{ Value string }{}
216216
gossh.Unmarshal(req.Payload, &payload)
217217
sess.cmd, _ = shlex.Split(payload.Value, true)
218+
219+
// If there's a session policy callback, we need to confirm before
220+
// accepting the session.
221+
if sess.sessReqCb != nil && !sess.sessReqCb(sess, req.Type) {
222+
sess.cmd = nil
223+
req.Reply(false, nil)
224+
continue
225+
}
226+
227+
sess.handled = true
228+
req.Reply(true, nil)
229+
218230
go func() {
219231
sess.handler(sess)
220232
sess.Exit(0)

ssh.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ package ssh
22

33
import (
44
"crypto/subtle"
5-
gossh "golang.org/x/crypto/ssh"
65
"net"
6+
7+
gossh "golang.org/x/crypto/ssh"
78
)
89

910
type Signal string
@@ -46,6 +47,9 @@ type KeyboardInteractiveHandler func(ctx Context, challenger gossh.KeyboardInter
4647
// PtyCallback is a hook for allowing PTY sessions.
4748
type PtyCallback func(ctx Context, pty Pty) bool
4849

50+
// SessionRequestCallback is a callback for allowing or denying SSH sessions.
51+
type SessionRequestCallback func(sess Session, requestType string) bool
52+
4953
// ConnCallback is a hook for new connections before handling.
5054
// It allows wrapping for timeouts and limiting by returning
5155
// the net.Conn that will be used as the underlying connection.

0 commit comments

Comments
 (0)