serve sftp: fix authentication on one connection blocking others - fixes #4882

Before this change, if one connection was authenticating this would
block any others from authenticating.

This was due to ssh.NewServerConn not being called in a go routine
after the Accept call.

This is fixed by running the ssh authentication in a go routine.

Thanks to @FiloSottile for advice on how to fix this.

See: https://github.com/golang/go/issues/43521
This commit is contained in:
Nick Craig-Wood 2021-01-05 17:14:40 +00:00
parent c66b901320
commit c553ad5158

View file

@ -78,23 +78,16 @@ func (s *server) getVFS(what string, sshConn *ssh.ServerConn) (VFS *vfs.VFS) {
return VFS return VFS
} }
func (s *server) acceptConnections() { // Accept a single connection - run in a go routine as the ssh
for { // authentication can block
nConn, err := s.listener.Accept() func (s *server) acceptConnection(nConn net.Conn) {
if err != nil {
if strings.Contains(err.Error(), "use of closed network connection") {
return
}
fs.Errorf(nil, "Failed to accept incoming connection: %v", err)
continue
}
what := describeConn(nConn) what := describeConn(nConn)
// Before use, a handshake must be performed on the incoming net.Conn. // Before use, a handshake must be performed on the incoming net.Conn.
sshConn, chans, reqs, err := ssh.NewServerConn(nConn, s.config) sshConn, chans, reqs, err := ssh.NewServerConn(nConn, s.config)
if err != nil { if err != nil {
fs.Errorf(what, "SSH login failed: %v", err) fs.Errorf(what, "SSH login failed: %v", err)
continue return
} }
fs.Infof(what, "SSH login from %s using %s", sshConn.User(), sshConn.ClientVersion()) fs.Infof(what, "SSH login from %s using %s", sshConn.User(), sshConn.ClientVersion())
@ -109,13 +102,27 @@ func (s *server) acceptConnections() {
if c.vfs == nil { if c.vfs == nil {
fs.Infof(what, "Closing unauthenticated connection (couldn't find VFS)") fs.Infof(what, "Closing unauthenticated connection (couldn't find VFS)")
_ = nConn.Close() _ = nConn.Close()
continue return
} }
c.handlers = newVFSHandler(c.vfs) c.handlers = newVFSHandler(c.vfs)
// Accept all channels // Accept all channels
go c.handleChannels(chans) go c.handleChannels(chans)
} }
// Accept connections and call them in a go routine
func (s *server) acceptConnections() {
for {
nConn, err := s.listener.Accept()
if err != nil {
if strings.Contains(err.Error(), "use of closed network connection") {
return
}
fs.Errorf(nil, "Failed to accept incoming connection: %v", err)
continue
}
go s.acceptConnection(nConn)
}
} }
// Based on example server code from golang.org/x/crypto/ssh and server_standalone // Based on example server code from golang.org/x/crypto/ssh and server_standalone