allow to disable SFTP service

Fixes #228
This commit is contained in:
Nicola Murino 2020-11-24 13:44:57 +01:00
parent 99cd1ccfe5
commit 0609188d3f
No known key found for this signature in database
GPG key ID: 2F1FB59433D5A8CB
9 changed files with 112 additions and 48 deletions

View file

@ -206,7 +206,8 @@ func init() {
This can be an absolute path or a path
relative to the current directory
`)
portableCmd.Flags().IntVarP(&portableSFTPDPort, "sftpd-port", "s", 0, "0 means a random unprivileged port")
portableCmd.Flags().IntVarP(&portableSFTPDPort, "sftpd-port", "s", 0, `0 means a random unprivileged port,
< 0 disabled`)
portableCmd.Flags().IntVar(&portableFTPDPort, "ftpd-port", -1, `0 means a random unprivileged port,
< 0 disabled`)
portableCmd.Flags().IntVar(&portableWebDAVPort, "webdav-port", -1, `0 means a random unprivileged port,
@ -237,7 +238,7 @@ The format is:
/dir::pattern1,pattern2.
For example: "/somedir::*.jpg,a*b?.png"`)
portableCmd.Flags().BoolVarP(&portableAdvertiseService, "advertise-service", "S", false,
`Advertise SFTP/FTP service using
`Advertise configured services using
multicast DNS`)
portableCmd.Flags().BoolVarP(&portableAdvertiseCredentials, "advertise-credentials", "C", false,
`If the SFTP/FTP service is

View file

@ -582,7 +582,7 @@ type ConnectionStatus struct {
Protocol string `json:"protocol"`
// active uploads/downloads
Transfers []ConnectionTransfer `json:"active_transfers,omitempty"`
// SSH command or WevDAV method
// SSH command or WebDAV method
Command string `json:"command,omitempty"`
}

View file

@ -240,6 +240,21 @@ func GetHTTPConfig() httpclient.Config {
return globalConf.HTTPConfig
}
// HasServicesToStart returns true if the config defines at least a service to start.
// Supported services are SFTP, FTP and WebDAV
func HasServicesToStart() bool {
if globalConf.SFTPD.BindPort > 0 {
return true
}
if globalConf.FTPD.BindPort > 0 {
return true
}
if globalConf.WebDAVD.BindPort > 0 {
return true
}
return false
}
func getRedactedGlobalConf() globalConfig {
conf := globalConf
conf.ProviderConf.Password = "[redacted]"

View file

@ -281,6 +281,33 @@ func TestSetGetConfig(t *testing.T) {
assert.Equal(t, webDavConf.CertificateKeyFile, config.GetWebDAVDConfig().CertificateKeyFile)
}
func TestServiceToStart(t *testing.T) {
configDir := ".."
err := config.LoadConfig(configDir, configName)
assert.NoError(t, err)
assert.True(t, config.HasServicesToStart())
sftpdConf := config.GetSFTPDConfig()
sftpdConf.BindPort = 0
config.SetSFTPDConfig(sftpdConf)
assert.False(t, config.HasServicesToStart())
ftpdConf := config.GetFTPDConfig()
ftpdConf.BindPort = 2121
config.SetFTPDConfig(ftpdConf)
assert.True(t, config.HasServicesToStart())
ftpdConf.BindPort = 0
config.SetFTPDConfig(ftpdConf)
webdavdConf := config.GetWebDAVDConfig()
webdavdConf.BindPort = 9000
config.SetWebDAVDConfig(webdavdConf)
assert.True(t, config.HasServicesToStart())
webdavdConf.BindPort = 0
config.SetWebDAVDConfig(webdavdConf)
assert.False(t, config.HasServicesToStart())
sftpdConf.BindPort = 2022
config.SetSFTPDConfig(sftpdConf)
assert.True(t, config.HasServicesToStart())
}
func TestConfigFromEnv(t *testing.T) {
os.Setenv("SFTPGO_SFTPD__BIND_ADDRESS", "127.0.0.1")
os.Setenv("SFTPGO_DATA_PROVIDER__PASSWORD_HASHING__ARGON2_OPTIONS__ITERATIONS", "41")

View file

@ -64,7 +64,7 @@ The configuration file contains the following sections:
- If `proxy_protocol` is set to 2 and we receive a proxy header from an IP that is not in the list then the connection will be rejected
- `post_connect_hook`, string. Absolute path to the command to execute or HTTP URL to notify. See [Post connect hook](./post-connect-hook.md) for more details. Leave empty to disable
- **"sftpd"**, the configuration for the SFTP server
- `bind_port`, integer. The port used for serving SFTP requests. Default: 2022
- `bind_port`, integer. The port used for serving SFTP requests. 0 means disabled. Default: 2022
- `bind_address`, string. Leave blank to listen on all available network interfaces. Default: ""
- `idle_timeout`, integer. Deprecated, please use the same key in `common` section.
- `max_auth_tries` integer. Maximum number of authentication attempts permitted per connection. If set to a negative number, the number of attempts is unlimited. If set to zero, the number of attempts is limited to 6.

View file

@ -19,7 +19,7 @@ Flags:
advertised via multicast DNS, this
flag allows to put username/password
inside the advertised TXT record
-S, --advertise-service Advertise SFTP/FTP service using
-S, --advertise-service Advertise configured services using
multicast DNS
--allowed-patterns stringArray Allowed file patterns case insensitive.
The format is:
@ -88,7 +88,8 @@ Flags:
parallel (default 2)
--s3-upload-part-size int The buffer size for multipart uploads
(MB) (default 5)
-s, --sftpd-port int 0 means a random unprivileged port
-s, --sftpd-port int 0 means a random unprivileged port,
< 0 disabled
-c, --ssh-commands strings SSH commands to enable.
"*" means any supported SSH command
including scp

View file

@ -2,6 +2,7 @@
package service
import (
"errors"
"fmt"
"io/ioutil"
"os"
@ -73,6 +74,12 @@ func (s *Service) Start() error {
logger.Error(logSender, "", "error loading configuration: %v", err)
}
}
if !config.HasServicesToStart() {
infoString := "No service configured, nothing to do"
logger.Info(logSender, "", infoString)
logger.InfoToConsole(infoString)
return errors.New(infoString)
}
common.Initialize(config.GetCommonConfig())
@ -115,15 +122,19 @@ func (s *Service) startServices() {
httpdConf := config.GetHTTPDConfig()
webDavDConf := config.GetWebDAVDConfig()
go func() {
logger.Debug(logSender, "", "initializing SFTP server with config %+v", sftpdConf)
if err := sftpdConf.Initialize(s.ConfigDir); err != nil {
logger.Error(logSender, "", "could not start SFTP server: %v", err)
logger.ErrorToConsole("could not start SFTP server: %v", err)
s.Error = err
}
s.Shutdown <- true
}()
if sftpdConf.BindPort > 0 {
go func() {
logger.Debug(logSender, "", "initializing SFTP server with config %+v", sftpdConf)
if err := sftpdConf.Initialize(s.ConfigDir); err != nil {
logger.Error(logSender, "", "could not start SFTP server: %v", err)
logger.ErrorToConsole("could not start SFTP server: %v", err)
s.Error = err
}
s.Shutdown <- true
}()
} else {
logger.Debug(logSender, "", "SFTP server not started, disabled in config file")
}
if httpdConf.BindPort > 0 {
go func() {
@ -162,7 +173,7 @@ func (s *Service) startServices() {
s.Shutdown <- true
}()
} else {
logger.Debug(logSender, "", "WevDAV server not started, disabled in config file")
logger.Debug(logSender, "", "WebDAV server not started, disabled in config file")
}
}

View file

@ -32,21 +32,7 @@ func (s *Service) StartPortableMode(sftpdPort, ftpPort, webdavPort int, enabledS
if err != nil {
fmt.Printf("error loading configuration file: %v using defaults\n", err)
}
if len(s.PortableUser.Username) == 0 {
s.PortableUser.Username = "user"
}
printablePassword := ""
if len(s.PortableUser.Password) > 0 {
printablePassword = "[redacted]"
}
if len(s.PortableUser.PublicKeys) == 0 && len(s.PortableUser.Password) == 0 {
var b strings.Builder
for i := 0; i < 8; i++ {
b.WriteRune(chars[rand.Intn(len(chars))])
}
s.PortableUser.Password = b.String()
printablePassword = s.PortableUser.Password
}
printablePassword := s.configurePortableUser()
dataProviderConf := config.GetProviderConf()
dataProviderConf.Driver = dataprovider.MemoryDataProviderName
dataProviderConf.Name = ""
@ -57,16 +43,19 @@ func (s *Service) StartPortableMode(sftpdPort, ftpPort, webdavPort int, enabledS
config.SetHTTPDConfig(httpdConf)
sftpdConf := config.GetSFTPDConfig()
sftpdConf.MaxAuthTries = 12
if sftpdPort > 0 {
sftpdConf.BindPort = sftpdPort
} else {
// dynamic ports starts from 49152
sftpdConf.BindPort = 49152 + rand.Intn(15000)
}
if utils.IsStringInSlice("*", enabledSSHCommands) {
sftpdConf.EnabledSSHCommands = sftpd.GetSupportedSSHCommands()
} else {
sftpdConf.EnabledSSHCommands = enabledSSHCommands
sftpdConf.BindPort = sftpdPort
if sftpdPort >= 0 {
if sftpdPort > 0 {
sftpdConf.BindPort = sftpdPort
} else {
// dynamic ports starts from 49152
sftpdConf.BindPort = 49152 + rand.Intn(15000)
}
if utils.IsStringInSlice("*", enabledSSHCommands) {
sftpdConf.EnabledSSHCommands = sftpd.GetSupportedSSHCommands()
} else {
sftpdConf.EnabledSSHCommands = enabledSSHCommands
}
}
config.SetSFTPDConfig(sftpdConf)
@ -102,8 +91,8 @@ func (s *Service) StartPortableMode(sftpdPort, ftpPort, webdavPort int, enabledS
s.advertiseServices(advertiseService, advertiseCredentials)
logger.InfoToConsole("Portable mode ready, SFTP port: %v, user: %#v, password: %#v, public keys: %v, directory: %#v, "+
"permissions: %+v, enabled ssh commands: %v file patterns filters: %+v %v", sftpdConf.BindPort, s.PortableUser.Username,
logger.InfoToConsole("Portable mode ready, user: %#v, password: %#v, public keys: %v, directory: %#v, "+
"permissions: %+v, enabled ssh commands: %v file patterns filters: %+v %v", s.PortableUser.Username,
printablePassword, s.PortableUser.PublicKeys, s.getPortableDirToServe(), s.PortableUser.Permissions,
sftpdConf.EnabledSSHCommands, s.PortableUser.Filters.FilePatterns, s.getServiceOptionalInfoString())
return nil
@ -111,15 +100,15 @@ func (s *Service) StartPortableMode(sftpdPort, ftpPort, webdavPort int, enabledS
func (s *Service) getServiceOptionalInfoString() string {
var info strings.Builder
if config.GetSFTPDConfig().BindPort > 0 {
info.WriteString(fmt.Sprintf("SFTP port: %v ", config.GetSFTPDConfig().BindPort))
}
if config.GetFTPDConfig().BindPort > 0 {
info.WriteString(fmt.Sprintf("FTP port: %v ", config.GetFTPDConfig().BindPort))
}
if config.GetWebDAVDConfig().BindPort > 0 {
if info.Len() == 0 {
info.WriteString(" ")
}
scheme := "http"
if len(config.GetWebDAVDConfig().CertificateFile) > 0 && len(config.GetWebDAVDConfig().CertificateKeyFile) > 0 {
if config.GetWebDAVDConfig().CertificateFile != "" && config.GetWebDAVDConfig().CertificateKeyFile != "" {
scheme = "https"
}
info.WriteString(fmt.Sprintf("WebDAV URL: %v://<your IP>:%v/%v",
@ -230,3 +219,23 @@ func (s *Service) getPortableDirToServe() string {
}
return dirToServe
}
// configures the portable user and return the printable password if any
func (s *Service) configurePortableUser() string {
if s.PortableUser.Username == "" {
s.PortableUser.Username = "user"
}
printablePassword := ""
if len(s.PortableUser.Password) > 0 {
printablePassword = "[redacted]"
}
if len(s.PortableUser.PublicKeys) == 0 && len(s.PortableUser.Password) == 0 {
var b strings.Builder
for i := 0; i < 8; i++ {
b.WriteRune(chars[rand.Intn(len(chars))])
}
s.PortableUser.Password = b.String()
printablePassword = s.PortableUser.Password
}
return printablePassword
}

View file

@ -73,7 +73,7 @@ type Configuration struct {
// Initialize configures and starts the WebDav server
func (c *Configuration) Initialize(configDir string) error {
var err error
logger.Debug(logSender, "", "initializing WevDav server with config %+v", *c)
logger.Debug(logSender, "", "initializing WebDAV server with config %+v", *c)
mimeTypeCache = mimeCache{
maxSize: c.Cache.MimeTypes.MaxSize,
mimeTypes: make(map[string]string),