config.go 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. // Package config manages the configuration.
  2. // Configuration is loaded from sftpgo.conf file.
  3. // If sftpgo.conf is not found or cannot be readed or decoded as json the default configuration is used.
  4. // The default configuration an be found inside the source tree:
  5. // https://github.com/drakkan/sftpgo/blob/master/sftpgo.conf
  6. package config
  7. import (
  8. "fmt"
  9. "strings"
  10. "github.com/drakkan/sftpgo/dataprovider"
  11. "github.com/drakkan/sftpgo/httpd"
  12. "github.com/drakkan/sftpgo/logger"
  13. "github.com/drakkan/sftpgo/sftpd"
  14. "github.com/drakkan/sftpgo/utils"
  15. "github.com/spf13/viper"
  16. )
  17. const (
  18. logSender = "config"
  19. // DefaultConfigName defines the name for the default config file.
  20. // This is the file name without extension, we use viper and so we
  21. // support all the config files format supported by viper
  22. DefaultConfigName = "sftpgo"
  23. // ConfigEnvPrefix defines a prefix that ENVIRONMENT variables will use
  24. configEnvPrefix = "sftpgo"
  25. )
  26. var (
  27. globalConf globalConfig
  28. defaultBanner = fmt.Sprintf("SFTPGo_%v", utils.GetAppVersion().Version)
  29. )
  30. type globalConfig struct {
  31. SFTPD sftpd.Configuration `json:"sftpd" mapstructure:"sftpd"`
  32. ProviderConf dataprovider.Config `json:"data_provider" mapstructure:"data_provider"`
  33. HTTPDConfig httpd.Conf `json:"httpd" mapstructure:"httpd"`
  34. }
  35. func init() {
  36. // create a default configuration to use if no config file is provided
  37. globalConf = globalConfig{
  38. SFTPD: sftpd.Configuration{
  39. Banner: defaultBanner,
  40. BindPort: 2022,
  41. BindAddress: "",
  42. IdleTimeout: 15,
  43. MaxAuthTries: 0,
  44. Umask: "0022",
  45. UploadMode: 0,
  46. Actions: sftpd.Actions{
  47. ExecuteOn: []string{},
  48. Command: "",
  49. HTTPNotificationURL: "",
  50. },
  51. Keys: []sftpd.Key{},
  52. IsSCPEnabled: false,
  53. KexAlgorithms: []string{},
  54. Ciphers: []string{},
  55. MACs: []string{},
  56. LoginBannerFile: "",
  57. EnabledSSHCommands: sftpd.GetDefaultSSHCommands(),
  58. KeyboardInteractiveProgram: "",
  59. ProxyProtocol: 0,
  60. },
  61. ProviderConf: dataprovider.Config{
  62. Driver: "sqlite",
  63. Name: "sftpgo.db",
  64. Host: "",
  65. Port: 5432,
  66. Username: "",
  67. Password: "",
  68. ConnectionString: "",
  69. UsersTable: "users",
  70. ManageUsers: 1,
  71. SSLMode: 0,
  72. TrackQuota: 1,
  73. PoolSize: 0,
  74. UsersBaseDir: "",
  75. Actions: dataprovider.Actions{
  76. ExecuteOn: []string{},
  77. Command: "",
  78. HTTPNotificationURL: "",
  79. },
  80. ExternalAuthProgram: "",
  81. ExternalAuthScope: 0,
  82. CredentialsPath: "credentials",
  83. PreLoginProgram: "",
  84. },
  85. HTTPDConfig: httpd.Conf{
  86. BindPort: 8080,
  87. BindAddress: "127.0.0.1",
  88. TemplatesPath: "templates",
  89. StaticFilesPath: "static",
  90. BackupsPath: "backups",
  91. AuthUserFile: "",
  92. CertificateFile: "",
  93. CertificateKeyFile: "",
  94. },
  95. }
  96. viper.SetEnvPrefix(configEnvPrefix)
  97. replacer := strings.NewReplacer(".", "__")
  98. viper.SetEnvKeyReplacer(replacer)
  99. viper.SetConfigName(DefaultConfigName)
  100. viper.AutomaticEnv()
  101. viper.AllowEmptyEnv(true)
  102. }
  103. // GetSFTPDConfig returns the configuration for the SFTP server
  104. func GetSFTPDConfig() sftpd.Configuration {
  105. return globalConf.SFTPD
  106. }
  107. // SetSFTPDConfig sets the configuration for the SFTP server
  108. func SetSFTPDConfig(config sftpd.Configuration) {
  109. globalConf.SFTPD = config
  110. }
  111. // GetHTTPDConfig returns the configuration for the HTTP server
  112. func GetHTTPDConfig() httpd.Conf {
  113. return globalConf.HTTPDConfig
  114. }
  115. // SetHTTPDConfig sets the configuration for the HTTP server
  116. func SetHTTPDConfig(config httpd.Conf) {
  117. globalConf.HTTPDConfig = config
  118. }
  119. //GetProviderConf returns the configuration for the data provider
  120. func GetProviderConf() dataprovider.Config {
  121. return globalConf.ProviderConf
  122. }
  123. //SetProviderConf sets the configuration for the data provider
  124. func SetProviderConf(config dataprovider.Config) {
  125. globalConf.ProviderConf = config
  126. }
  127. func getRedactedGlobalConf() globalConfig {
  128. conf := globalConf
  129. conf.ProviderConf.Password = "[redacted]"
  130. return conf
  131. }
  132. // LoadConfig loads the configuration
  133. // configDir will be added to the configuration search paths.
  134. // The search path contains by default the current directory and on linux it contains
  135. // $HOME/.config/sftpgo and /etc/sftpgo too.
  136. // configName is the name of the configuration to search without extension
  137. func LoadConfig(configDir, configName string) error {
  138. var err error
  139. viper.AddConfigPath(configDir)
  140. setViperAdditionalConfigPaths()
  141. viper.AddConfigPath(".")
  142. viper.SetConfigName(configName)
  143. if err = viper.ReadInConfig(); err != nil {
  144. logger.Warn(logSender, "", "error loading configuration file: %v. Default configuration will be used: %+v",
  145. err, getRedactedGlobalConf())
  146. logger.WarnToConsole("error loading configuration file: %v. Default configuration will be used.", err)
  147. return err
  148. }
  149. err = viper.Unmarshal(&globalConf)
  150. if err != nil {
  151. logger.Warn(logSender, "", "error parsing configuration file: %v. Default configuration will be used: %+v",
  152. err, getRedactedGlobalConf())
  153. logger.WarnToConsole("error parsing configuration file: %v. Default configuration will be used.", err)
  154. return err
  155. }
  156. if strings.TrimSpace(globalConf.SFTPD.Banner) == "" {
  157. globalConf.SFTPD.Banner = defaultBanner
  158. }
  159. if globalConf.SFTPD.UploadMode < 0 || globalConf.SFTPD.UploadMode > 2 {
  160. err = fmt.Errorf("invalid upload_mode 0, 1 and 2 are supported, configured: %v reset upload_mode to 0",
  161. globalConf.SFTPD.UploadMode)
  162. globalConf.SFTPD.UploadMode = 0
  163. logger.Warn(logSender, "", "Configuration error: %v", err)
  164. logger.WarnToConsole("Configuration error: %v", err)
  165. }
  166. if globalConf.SFTPD.ProxyProtocol < 0 || globalConf.SFTPD.ProxyProtocol > 2 {
  167. err = fmt.Errorf("invalid proxy_protocol 0, 1 and 2 are supported, configured: %v reset proxy_protocol to 0",
  168. globalConf.SFTPD.ProxyProtocol)
  169. globalConf.SFTPD.ProxyProtocol = 0
  170. logger.Warn(logSender, "", "Configuration error: %v", err)
  171. logger.WarnToConsole("Configuration error: %v", err)
  172. }
  173. if globalConf.ProviderConf.ExternalAuthScope < 0 || globalConf.ProviderConf.ExternalAuthScope > 7 {
  174. err = fmt.Errorf("invalid external_auth_scope: %v reset to 0", globalConf.ProviderConf.ExternalAuthScope)
  175. globalConf.ProviderConf.ExternalAuthScope = 0
  176. logger.Warn(logSender, "", "Configuration error: %v", err)
  177. logger.WarnToConsole("Configuration error: %v", err)
  178. }
  179. if len(globalConf.ProviderConf.CredentialsPath) == 0 {
  180. err = fmt.Errorf("invalid credentials path, reset to \"credentials\"")
  181. globalConf.ProviderConf.CredentialsPath = "credentials"
  182. logger.Warn(logSender, "", "Configuration error: %v", err)
  183. logger.WarnToConsole("Configuration error: %v", err)
  184. }
  185. logger.Debug(logSender, "", "config file used: '%v', config loaded: %+v", viper.ConfigFileUsed(), getRedactedGlobalConf())
  186. return err
  187. }