@@ -476,6 +476,12 @@ func (a *agent) init(ctx context.Context) {
476
476
},
477
477
SubsystemHandlers : map [string ]ssh.SubsystemHandler {
478
478
"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.
479
485
session .DisablePTYEmulation ()
480
486
481
487
var opts []sftp.ServerOption
@@ -484,22 +490,33 @@ func (a *agent) init(ctx context.Context) {
484
490
// https://github.com/coder/coder/issues/3620
485
491
u , err := user .Current ()
486
492
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 ))
488
494
} else {
489
495
opts = append (opts , sftp .WithServerWorkingDirectory (u .HomeDir ))
490
496
}
491
497
492
498
server , err := sftp .NewServer (session , opts ... )
493
499
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 ))
495
501
return
496
502
}
497
503
defer server .Close ()
504
+
498
505
err = server .Serve ()
499
506
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 )
500
516
return
501
517
}
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 )
503
520
},
504
521
},
505
522
}
0 commit comments