(logger slog.Logger, session ssh.Session)
| 857 | } |
| 858 | |
| 859 | func (s *Server) sftpHandler(logger slog.Logger, session ssh.Session) error { |
| 860 | s.metrics.sftpConnectionsTotal.Add(1) |
| 861 | |
| 862 | ctx := session.Context() |
| 863 | |
| 864 | // Typically sftp sessions don't request a TTY, but if they do, |
| 865 | // we must ensure the gliderlabs/ssh CRLF emulation is disabled. |
| 866 | // Otherwise sftp will be broken. This can happen if a user sets |
| 867 | // `RequestTTY force` in their SSH config. |
| 868 | session.DisablePTYEmulation() |
| 869 | |
| 870 | var opts []sftp.ServerOption |
| 871 | // Change current working directory to the configured |
| 872 | // directory (or home directory if not set) so that SFTP |
| 873 | // connections land there. |
| 874 | dir := s.config.WorkingDirectory() |
| 875 | if dir == "" { |
| 876 | var err error |
| 877 | dir, err = userHomeDir() |
| 878 | if err != nil { |
| 879 | logger.Warn(ctx, "get sftp working directory failed, unable to get home dir", slog.Error(err)) |
| 880 | } |
| 881 | } |
| 882 | if dir != "" { |
| 883 | opts = append(opts, sftp.WithServerWorkingDirectory(dir)) |
| 884 | } |
| 885 | |
| 886 | server, err := sftp.NewServer(session, opts...) |
| 887 | if err != nil { |
| 888 | logger.Debug(ctx, "initialize sftp server", slog.Error(err)) |
| 889 | return xerrors.Errorf("initialize sftp server: %w", err) |
| 890 | } |
| 891 | defer server.Close() |
| 892 | |
| 893 | err = server.Serve() |
| 894 | if err == nil || errors.Is(err, io.EOF) { |
| 895 | // Unless we call `session.Exit(0)` here, the client won't |
| 896 | // receive `exit-status` because `(*sftp.Server).Close()` |
| 897 | // calls `Close()` on the underlying connection (session), |
| 898 | // which actually calls `channel.Close()` because it isn't |
| 899 | // wrapped. This causes sftp clients to receive a non-zero |
| 900 | // exit code. Typically sftp clients don't echo this exit |
| 901 | // code but `scp` on macOS does (when using the default |
| 902 | // SFTP backend). |
| 903 | _ = session.Exit(0) |
| 904 | return nil |
| 905 | } |
| 906 | logger.Warn(ctx, "sftp server closed with error", slog.Error(err)) |
| 907 | s.metrics.sftpServerErrors.Add(1) |
| 908 | _ = session.Exit(1) |
| 909 | return xerrors.Errorf("sftp server closed with error: %w", err) |
| 910 | } |
| 911 | |
| 912 | func (s *Server) CommandEnv(ei usershell.EnvInfoer, addEnv []string) (shell, dir string, env []string, err error) { |
| 913 | if ei == nil { |
no test coverage detected