subsystem.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. // Copyright (C) 2019 Nicola Murino
  2. //
  3. // This program is free software: you can redistribute it and/or modify
  4. // it under the terms of the GNU Affero General Public License as published
  5. // by the Free Software Foundation, version 3.
  6. //
  7. // This program is distributed in the hope that it will be useful,
  8. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. // GNU Affero General Public License for more details.
  11. //
  12. // You should have received a copy of the GNU Affero General Public License
  13. // along with this program. If not, see <https://www.gnu.org/licenses/>.
  14. package sftpd
  15. import (
  16. "io"
  17. "net"
  18. "github.com/pkg/sftp"
  19. "github.com/drakkan/sftpgo/v2/internal/common"
  20. "github.com/drakkan/sftpgo/v2/internal/dataprovider"
  21. "github.com/drakkan/sftpgo/v2/internal/logger"
  22. )
  23. type subsystemChannel struct {
  24. reader io.Reader
  25. writer io.Writer
  26. }
  27. func (s *subsystemChannel) Read(p []byte) (int, error) {
  28. return s.reader.Read(p)
  29. }
  30. func (s *subsystemChannel) Write(p []byte) (int, error) {
  31. return s.writer.Write(p)
  32. }
  33. func (s *subsystemChannel) Close() error {
  34. return nil
  35. }
  36. func newSubsystemChannel(reader io.Reader, writer io.Writer) *subsystemChannel {
  37. return &subsystemChannel{
  38. reader: reader,
  39. writer: writer,
  40. }
  41. }
  42. // ServeSubSystemConnection handles a connection as SSH subsystem
  43. func ServeSubSystemConnection(user *dataprovider.User, connectionID string, reader io.Reader, writer io.Writer) error {
  44. err := user.CheckFsRoot(connectionID)
  45. if err != nil {
  46. errClose := user.CloseFs()
  47. logger.Warn(logSender, connectionID, "unable to check fs root: %v close fs error: %v", err, errClose)
  48. return err
  49. }
  50. connection := &Connection{
  51. BaseConnection: common.NewBaseConnection(connectionID, common.ProtocolSFTP, "", "", *user),
  52. ClientVersion: "",
  53. RemoteAddr: &net.IPAddr{},
  54. LocalAddr: &net.IPAddr{},
  55. channel: newSubsystemChannel(reader, writer),
  56. }
  57. err = common.Connections.Add(connection)
  58. if err != nil {
  59. errClose := user.CloseFs()
  60. logger.Warn(logSender, connectionID, "unable to add connection: %v close fs error: %v", err, errClose)
  61. return err
  62. }
  63. defer common.Connections.Remove(connection.GetID())
  64. dataprovider.UpdateLastLogin(user)
  65. sftp.SetSFTPExtensions(sftpExtensions...) //nolint:errcheck
  66. server := sftp.NewRequestServer(connection.channel, sftp.Handlers{
  67. FileGet: connection,
  68. FilePut: connection,
  69. FileCmd: connection,
  70. FileList: connection,
  71. }, sftp.WithRSAllocator())
  72. defer server.Close()
  73. return server.Serve()
  74. }