service_portable.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. // +build !noportable
  2. package service
  3. import (
  4. "fmt"
  5. "math/rand"
  6. "os"
  7. "os/signal"
  8. "path/filepath"
  9. "strings"
  10. "syscall"
  11. "time"
  12. "github.com/grandcat/zeroconf"
  13. "github.com/drakkan/sftpgo/config"
  14. "github.com/drakkan/sftpgo/dataprovider"
  15. "github.com/drakkan/sftpgo/logger"
  16. "github.com/drakkan/sftpgo/sftpd"
  17. "github.com/drakkan/sftpgo/utils"
  18. )
  19. // StartPortableMode starts the service in portable mode
  20. func (s *Service) StartPortableMode(sftpdPort int, enabledSSHCommands []string, advertiseService, advertiseCredentials bool) error {
  21. if s.PortableMode != 1 {
  22. return fmt.Errorf("service is not configured for portable mode")
  23. }
  24. var err error
  25. rand.Seed(time.Now().UnixNano())
  26. if len(s.PortableUser.Username) == 0 {
  27. s.PortableUser.Username = "user"
  28. }
  29. if len(s.PortableUser.PublicKeys) == 0 && len(s.PortableUser.Password) == 0 {
  30. var b strings.Builder
  31. for i := 0; i < 8; i++ {
  32. b.WriteRune(chars[rand.Intn(len(chars))])
  33. }
  34. s.PortableUser.Password = b.String()
  35. }
  36. dataProviderConf := config.GetProviderConf()
  37. dataProviderConf.Driver = dataprovider.MemoryDataProviderName
  38. dataProviderConf.Name = ""
  39. dataProviderConf.CredentialsPath = filepath.Join(os.TempDir(), "credentials")
  40. config.SetProviderConf(dataProviderConf)
  41. httpdConf := config.GetHTTPDConfig()
  42. httpdConf.BindPort = 0
  43. config.SetHTTPDConfig(httpdConf)
  44. sftpdConf := config.GetSFTPDConfig()
  45. sftpdConf.MaxAuthTries = 12
  46. if sftpdPort > 0 {
  47. sftpdConf.BindPort = sftpdPort
  48. } else {
  49. // dynamic ports starts from 49152
  50. sftpdConf.BindPort = 49152 + rand.Intn(15000)
  51. }
  52. if utils.IsStringInSlice("*", enabledSSHCommands) {
  53. sftpdConf.EnabledSSHCommands = sftpd.GetSupportedSSHCommands()
  54. } else {
  55. sftpdConf.EnabledSSHCommands = enabledSSHCommands
  56. }
  57. config.SetSFTPDConfig(sftpdConf)
  58. err = s.Start()
  59. if err != nil {
  60. return err
  61. }
  62. var mDNSService *zeroconf.Server
  63. if advertiseService {
  64. version := utils.GetAppVersion()
  65. meta := []string{
  66. fmt.Sprintf("version=%v", version.GetVersionAsString()),
  67. }
  68. if advertiseCredentials {
  69. logger.InfoToConsole("Advertising credentials via multicast DNS")
  70. meta = append(meta, fmt.Sprintf("user=%v", s.PortableUser.Username))
  71. if len(s.PortableUser.Password) > 0 {
  72. meta = append(meta, fmt.Sprintf("password=%v", s.PortableUser.Password))
  73. } else {
  74. logger.InfoToConsole("Unable to advertise key based credentials via multicast DNS, we don't have the private key")
  75. }
  76. }
  77. mDNSService, err = zeroconf.Register(
  78. fmt.Sprintf("SFTPGo portable %v", sftpdConf.BindPort), // service instance name
  79. "_sftp-ssh._tcp", // service type and protocol
  80. "local.", // service domain
  81. sftpdConf.BindPort, // service port
  82. meta, // service metadata
  83. nil, // register on all network interfaces
  84. )
  85. if err != nil {
  86. mDNSService = nil
  87. logger.WarnToConsole("Unable to advertise SFTP service via multicast DNS: %v", err)
  88. } else {
  89. logger.InfoToConsole("SFTP service advertised via multicast DNS")
  90. }
  91. }
  92. sig := make(chan os.Signal, 1)
  93. signal.Notify(sig, os.Interrupt, syscall.SIGTERM)
  94. go func() {
  95. <-sig
  96. if mDNSService != nil {
  97. logger.InfoToConsole("unregistering multicast DNS service")
  98. mDNSService.Shutdown()
  99. }
  100. s.Stop()
  101. }()
  102. logger.InfoToConsole("Portable mode ready, SFTP port: %v, user: %#v, password: %#v, public keys: %v, directory: %#v, "+
  103. "permissions: %+v, enabled ssh commands: %v file extensions filters: %+v", sftpdConf.BindPort, s.PortableUser.Username,
  104. s.PortableUser.Password, s.PortableUser.PublicKeys, s.getPortableDirToServe(), s.PortableUser.Permissions,
  105. sftpdConf.EnabledSSHCommands, s.PortableUser.Filters.FileExtensions)
  106. return nil
  107. }
  108. func (s *Service) getPortableDirToServe() string {
  109. var dirToServe string
  110. if s.PortableUser.FsConfig.Provider == 1 {
  111. dirToServe = s.PortableUser.FsConfig.S3Config.KeyPrefix
  112. } else if s.PortableUser.FsConfig.Provider == 2 {
  113. dirToServe = s.PortableUser.FsConfig.GCSConfig.KeyPrefix
  114. } else {
  115. dirToServe = s.PortableUser.HomeDir
  116. }
  117. return dirToServe
  118. }