Skip to content

Commit fd8d529

Browse files
Maisem AliiQQBot
authored andcommitted
ssh: add ErrDenied as a way to indicate auth termination
Signed-off-by: Maisem Ali <[email protected]>
1 parent 64b3897 commit fd8d529

File tree

1 file changed

+26
-6
lines changed

1 file changed

+26
-6
lines changed

ssh/server.go

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ type ServerConfig struct {
7676
// attempts to authenticate with auth method "none".
7777
// NoClientAuth must also be set to true for this be used, or
7878
// this func is unused.
79+
// If the function returns ErrDenied, the connection is terminated.
7980
NoClientAuthCallback func(ConnMetadata) (*Permissions, error)
8081

8182
// MaxAuthTries specifies the maximum number of authentication attempts
@@ -86,6 +87,7 @@ type ServerConfig struct {
8687

8788
// PasswordCallback, if non-nil, is called when a user
8889
// attempts to authenticate using a password.
90+
// If the function returns ErrDenied, the connection is terminated.
8991
PasswordCallback func(conn ConnMetadata, password []byte) (*Permissions, error)
9092

9193
// PublicKeyCallback, if non-nil, is called when a client
@@ -96,6 +98,7 @@ type ServerConfig struct {
9698
// offered is in fact used to authenticate. To record any data
9799
// depending on the public key, store it inside a
98100
// Permissions.Extensions entry.
101+
// If the function returns ErrDenied, the connection is terminated.
99102
PublicKeyCallback func(conn ConnMetadata, key PublicKey) (*Permissions, error)
100103

101104
// KeyboardInteractiveCallback, if non-nil, is called when
@@ -105,6 +108,7 @@ type ServerConfig struct {
105108
// Challenge rounds. To avoid information leaks, the client
106109
// should be presented a challenge even if the user is
107110
// unknown.
111+
// If the function returns ErrDenied, the connection is terminated.
108112
KeyboardInteractiveCallback func(conn ConnMetadata, client KeyboardInteractiveChallenge) (*Permissions, error)
109113

110114
// AuthLogCallback, if non-nil, is called to log all authentication
@@ -397,12 +401,19 @@ func (l ServerAuthError) Error() string {
397401
return "[" + strings.Join(errs, ", ") + "]"
398402
}
399403

400-
// ErrNoAuth is the error value returned if no
401-
// authentication method has been passed yet. This happens as a normal
402-
// part of the authentication loop, since the client first tries
403-
// 'none' authentication to discover available methods.
404-
// It is returned in ServerAuthError.Errors from NewServerConn.
405-
var ErrNoAuth = errors.New("ssh: no auth passed yet")
404+
var (
405+
// ErrDenied can be returned from an authentication callback to inform the
406+
// client that access is denied and that no further attempt will be accepted
407+
// on the connection.
408+
ErrDenied = errors.New("ssh: access denied")
409+
410+
// ErrNoAuth is the error value returned if no
411+
// authentication method has been passed yet. This happens as a normal
412+
// part of the authentication loop, since the client first tries
413+
// 'none' authentication to discover available methods.
414+
// It is returned in ServerAuthError.Errors from NewServerConn.
415+
ErrNoAuth = errors.New("ssh: no auth passed yet")
416+
)
406417

407418
func (s *connection) serverAuthenticate(config *ServerConfig) (*Permissions, error) {
408419
sessionID := s.transport.getSessionID()
@@ -651,6 +662,15 @@ userAuthLoop:
651662
break userAuthLoop
652663
}
653664

665+
if errors.Is(authErr, ErrDenied) {
666+
var failureMsg userAuthFailureMsg
667+
if err := s.transport.writePacket(Marshal(failureMsg)); err != nil {
668+
return nil, err
669+
}
670+
671+
return nil, nil
672+
}
673+
654674
authFailures++
655675
if config.MaxAuthTries > 0 && authFailures >= config.MaxAuthTries {
656676
// If we have hit the max attempts, don't bother sending the

0 commit comments

Comments
 (0)