@@ -476,6 +476,12 @@ func (a *agent) init(ctx context.Context) {
476476 },
477477 SubsystemHandlers : map [string ]ssh.SubsystemHandler {
478478 "sftp" : func (session ssh.Session ) {
479+ ctx := session .Context ()
480+
481+ // Typically sftp sessions don't request a TTY, but if they do,
482+ // we must ensure the gliderlabs/ssh CRLF emulation is disabled.
483+ // Otherwise sftp will be broken. This can happen if a user sets
484+ // `RequestTTY force` in their SSH config.
479485 session .DisablePTYEmulation ()
480486
481487 var opts []sftp.ServerOption
@@ -484,22 +490,33 @@ func (a *agent) init(ctx context.Context) {
484490 // https://github.com/coder/coder/issues/3620
485491 u , err := user .Current ()
486492 if err != nil {
487- a . logger .Warn (ctx , "get sftp working directory failed, unable to get current user" , slog .Error (err ))
493+ sshLogger .Warn (ctx , "get sftp working directory failed, unable to get current user" , slog .Error (err ))
488494 } else {
489495 opts = append (opts , sftp .WithServerWorkingDirectory (u .HomeDir ))
490496 }
491497
492498 server , err := sftp .NewServer (session , opts ... )
493499 if err != nil {
494- a . logger . Debug (session . Context () , "initialize sftp server" , slog .Error (err ))
500+ sshLogger . Debug (ctx , "initialize sftp server" , slog .Error (err ))
495501 return
496502 }
497503 defer server .Close ()
504+
498505 err = server .Serve ()
499506 if errors .Is (err , io .EOF ) {
507+ // Unless we call `session.Exit(0)` here, the client won't
508+ // receive `exit-status` because `(*sftp.Server).Close()`
509+ // calls `Close()` on the underlying connection (session),
510+ // which actually calls `channel.Close()` because it isn't
511+ // wrapped. This causes sftp clients to receive a non-zero
512+ // exit code. Typically sftp clients don't echo this exit
513+ // code but `scp` on macOS does (when using the default
514+ // SFTP backend).
515+ _ = session .Exit (0 )
500516 return
501517 }
502- a .logger .Debug (session .Context (), "sftp server exited with error" , slog .Error (err ))
518+ sshLogger .Warn (ctx , "sftp server closed with error" , slog .Error (err ))
519+ _ = session .Exit (1 )
503520 },
504521 },
505522 }
0 commit comments