mirror of
https://github.com/tailscale/tailscale.git
synced 2024-11-29 04:55:31 +00:00
ssh/tailssh: use a local error instead of gossh.ErrDenied (#10743)
ErrDenied was added in [our fork of
x/crypto/ssh](acc6f8fe8d
)
to short-circuit auth attempts once one fails.
In the case of our callbacks, this error is returned when SSH policy
check determines that a connection should not be allowed. Both
`NoClientAuthCallback` and `PublicKeyHandler` check the policy and will
fail anyway. The `fakePasswordHandler` returns true only if
`NoClientAuthCallback` succeeds the policy check, so it checks it
indirectly too.
The difference here is that a client might attempt all 2-3 auth methods
instead of just `none` but will fail to authenticate regardless.
Updates #8593
Signed-off-by: Andrew Lytvynov <awly@tailscale.com>
This commit is contained in:
parent
124dc10261
commit
29e98e18f8
@ -254,7 +254,7 @@ func (c *conn) vlogf(format string, args ...any) {
|
|||||||
|
|
||||||
// isAuthorized walks through the action chain and returns nil if the connection
|
// isAuthorized walks through the action chain and returns nil if the connection
|
||||||
// is authorized. If the connection is not authorized, it returns
|
// is authorized. If the connection is not authorized, it returns
|
||||||
// gossh.ErrDenied. If the action chain resolution fails, it returns the
|
// errDenied. If the action chain resolution fails, it returns the
|
||||||
// resolution error.
|
// resolution error.
|
||||||
func (c *conn) isAuthorized(ctx ssh.Context) error {
|
func (c *conn) isAuthorized(ctx ssh.Context) error {
|
||||||
action := c.currentAction
|
action := c.currentAction
|
||||||
@ -266,7 +266,7 @@ func (c *conn) isAuthorized(ctx ssh.Context) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if action.Reject || action.HoldAndDelegate == "" {
|
if action.Reject || action.HoldAndDelegate == "" {
|
||||||
return gossh.ErrDenied
|
return errDenied
|
||||||
}
|
}
|
||||||
var err error
|
var err error
|
||||||
action, err = c.resolveNextAction(ctx)
|
action, err = c.resolveNextAction(ctx)
|
||||||
@ -281,6 +281,10 @@ func (c *conn) isAuthorized(ctx ssh.Context) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// errDenied is returned by auth callbacks when a connection is denied by the
|
||||||
|
// policy.
|
||||||
|
var errDenied = errors.New("ssh: access denied")
|
||||||
|
|
||||||
// errPubKeyRequired is returned by NoClientAuthCallback to make the client
|
// errPubKeyRequired is returned by NoClientAuthCallback to make the client
|
||||||
// resort to public-key auth; not user visible.
|
// resort to public-key auth; not user visible.
|
||||||
var errPubKeyRequired = errors.New("ssh publickey required")
|
var errPubKeyRequired = errors.New("ssh publickey required")
|
||||||
@ -293,7 +297,7 @@ func (c *conn) isAuthorized(ctx ssh.Context) error {
|
|||||||
// starting it afresh). It returns an error if the policy evaluation fails, or
|
// starting it afresh). It returns an error if the policy evaluation fails, or
|
||||||
// if the decision is "reject"
|
// if the decision is "reject"
|
||||||
//
|
//
|
||||||
// It either returns nil (accept) or errPubKeyRequired or gossh.ErrDenied
|
// It either returns nil (accept) or errPubKeyRequired or errDenied
|
||||||
// (reject). The errors may be wrapped.
|
// (reject). The errors may be wrapped.
|
||||||
func (c *conn) NoClientAuthCallback(ctx ssh.Context) error {
|
func (c *conn) NoClientAuthCallback(ctx ssh.Context) error {
|
||||||
if c.insecureSkipTailscaleAuth {
|
if c.insecureSkipTailscaleAuth {
|
||||||
@ -360,18 +364,18 @@ func (c *conn) PublicKeyHandler(ctx ssh.Context, pubKey ssh.PublicKey) error {
|
|||||||
// pubKey. It returns nil if the matching policy action is Accept or
|
// pubKey. It returns nil if the matching policy action is Accept or
|
||||||
// HoldAndDelegate. If pubKey is nil, there was no policy match but there is a
|
// HoldAndDelegate. If pubKey is nil, there was no policy match but there is a
|
||||||
// policy that might match a public key it returns errPubKeyRequired. Otherwise,
|
// policy that might match a public key it returns errPubKeyRequired. Otherwise,
|
||||||
// it returns gossh.ErrDenied.
|
// it returns errDenied.
|
||||||
func (c *conn) doPolicyAuth(ctx ssh.Context, pubKey ssh.PublicKey) error {
|
func (c *conn) doPolicyAuth(ctx ssh.Context, pubKey ssh.PublicKey) error {
|
||||||
if err := c.setInfo(ctx); err != nil {
|
if err := c.setInfo(ctx); err != nil {
|
||||||
c.logf("failed to get conninfo: %v", err)
|
c.logf("failed to get conninfo: %v", err)
|
||||||
return gossh.ErrDenied
|
return errDenied
|
||||||
}
|
}
|
||||||
a, localUser, err := c.evaluatePolicy(pubKey)
|
a, localUser, err := c.evaluatePolicy(pubKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if pubKey == nil && c.havePubKeyPolicy() {
|
if pubKey == nil && c.havePubKeyPolicy() {
|
||||||
return errPubKeyRequired
|
return errPubKeyRequired
|
||||||
}
|
}
|
||||||
return fmt.Errorf("%w: %v", gossh.ErrDenied, err)
|
return fmt.Errorf("%w: %v", errDenied, err)
|
||||||
}
|
}
|
||||||
c.action0 = a
|
c.action0 = a
|
||||||
c.currentAction = a
|
c.currentAction = a
|
||||||
@ -402,10 +406,10 @@ func (c *conn) doPolicyAuth(ctx ssh.Context, pubKey ssh.PublicKey) error {
|
|||||||
}
|
}
|
||||||
if a.Reject {
|
if a.Reject {
|
||||||
c.finalAction = a
|
c.finalAction = a
|
||||||
return gossh.ErrDenied
|
return errDenied
|
||||||
}
|
}
|
||||||
// Shouldn't get here, but:
|
// Shouldn't get here, but:
|
||||||
return gossh.ErrDenied
|
return errDenied
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServerConfig implements ssh.ServerConfigCallback.
|
// ServerConfig implements ssh.ServerConfigCallback.
|
||||||
@ -423,7 +427,7 @@ func (srv *server) newConn() (*conn, error) {
|
|||||||
// Stop accepting new connections.
|
// Stop accepting new connections.
|
||||||
// Connections in the auth phase are handled in handleConnPostSSHAuth.
|
// Connections in the auth phase are handled in handleConnPostSSHAuth.
|
||||||
// Existing sessions are terminated by Shutdown.
|
// Existing sessions are terminated by Shutdown.
|
||||||
return nil, gossh.ErrDenied
|
return nil, errDenied
|
||||||
}
|
}
|
||||||
srv.mu.Unlock()
|
srv.mu.Unlock()
|
||||||
c := &conn{srv: srv}
|
c := &conn{srv: srv}
|
||||||
|
Loading…
Reference in New Issue
Block a user