diff --git a/internal/command/command.go b/internal/command/command.go index fcf2da1f..512c2d4e 100644 --- a/internal/command/command.go +++ b/internal/command/command.go @@ -35,7 +35,6 @@ const ( HookStartup = "startup" HookPostConnect = "post_connect" HookPostDisconnect = "post_disconnect" - HookDataRetention = "data_retention" HookCheckPassword = "check_password" HookPreLogin = "pre_login" HookPostLogin = "post_login" @@ -46,7 +45,7 @@ const ( var ( config Config supportedHooks = []string{HookFsActions, HookProviderActions, HookStartup, HookPostConnect, HookPostDisconnect, - HookDataRetention, HookCheckPassword, HookPreLogin, HookPostLogin, HookExternalAuth, HookKeyboardInteractive} + HookCheckPassword, HookPreLogin, HookPostLogin, HookExternalAuth, HookKeyboardInteractive} ) // Command define the configuration for a specific commands diff --git a/internal/common/common.go b/internal/common/common.go index 299776ba..c6abbd90 100644 --- a/internal/common/common.go +++ b/internal/common/common.go @@ -615,9 +615,6 @@ type Configuration struct { // Absolute path to an external program or an HTTP URL to invoke after an SSH/FTP connection ends. // Leave empty do disable. PostDisconnectHook string `json:"post_disconnect_hook" mapstructure:"post_disconnect_hook"` - // Absolute path to an external program or an HTTP URL to invoke after a data retention check completes. - // Leave empty do disable. - DataRetentionHook string `json:"data_retention_hook" mapstructure:"data_retention_hook"` // Maximum number of concurrent client connections. 0 means unlimited MaxTotalConnections int `json:"max_total_connections" mapstructure:"max_total_connections"` // Maximum number of concurrent client connections from the same host (IP). 0 means unlimited diff --git a/internal/config/config.go b/internal/config/config.go index 62a32ecf..d413c265 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -217,7 +217,6 @@ func Init() { ProxySkipped: []string{}, PostConnectHook: "", PostDisconnectHook: "", - DataRetentionHook: "", MaxTotalConnections: 0, MaxPerHostConnections: 20, AllowListStatus: 0, @@ -645,7 +644,6 @@ func getRedactedGlobalConf() globalConfig { conf.Common.StartupHook = util.GetRedactedURL(conf.Common.StartupHook) conf.Common.PostConnectHook = util.GetRedactedURL(conf.Common.PostConnectHook) conf.Common.PostDisconnectHook = util.GetRedactedURL(conf.Common.PostDisconnectHook) - conf.Common.DataRetentionHook = util.GetRedactedURL(conf.Common.DataRetentionHook) conf.SFTPD.KeyboardInteractiveHook = util.GetRedactedURL(conf.SFTPD.KeyboardInteractiveHook) conf.HTTPDConfig.SigningPassphrase = getRedactedPassword(conf.HTTPDConfig.SigningPassphrase) conf.HTTPDConfig.Setup.InstallationCode = getRedactedPassword(conf.HTTPDConfig.Setup.InstallationCode) @@ -2066,7 +2064,6 @@ func setViperDefaults() { viper.SetDefault("common.proxy_skipped", globalConf.Common.ProxySkipped) viper.SetDefault("common.post_connect_hook", globalConf.Common.PostConnectHook) viper.SetDefault("common.post_disconnect_hook", globalConf.Common.PostDisconnectHook) - viper.SetDefault("common.data_retention_hook", globalConf.Common.DataRetentionHook) viper.SetDefault("common.max_total_connections", globalConf.Common.MaxTotalConnections) viper.SetDefault("common.max_per_host_connections", globalConf.Common.MaxPerHostConnections) viper.SetDefault("common.allowlist_status", globalConf.Common.AllowListStatus) diff --git a/internal/sftpd/server.go b/internal/sftpd/server.go index bd4dfca2..5bf03646 100644 --- a/internal/sftpd/server.go +++ b/internal/sftpd/server.go @@ -32,6 +32,7 @@ import ( "time" "github.com/pkg/sftp" + "github.com/rs/xid" "github.com/sftpgo/sdk/plugin/notifier" "golang.org/x/crypto/ssh" @@ -563,7 +564,7 @@ func (c *Configuration) configureKeyboardInteractiveAuth(serverConfig *ssh.Serve } // AcceptInboundConnection handles an inbound connection to the server instance and determines if the request should be served or not. -func (c *Configuration) AcceptInboundConnection(conn net.Conn, config *ssh.ServerConfig) { +func (c *Configuration) AcceptInboundConnection(conn net.Conn, config *ssh.ServerConfig) { //nolint:gocyclo defer func() { if r := recover(); r != nil { logger.Error(logSender, "", "panic in AcceptInboundConnection: %q stack trace: %v", r, string(debug.Stack())) @@ -600,7 +601,7 @@ func (c *Configuration) AcceptInboundConnection(conn net.Conn, config *ssh.Serve json.Unmarshal(util.StringToBytes(sconn.Permissions.Extensions["sftpgo_user"]), &user) //nolint:errcheck loginType := sconn.Permissions.Extensions["sftpgo_login_method"] - connectionID := hex.EncodeToString(sconn.SessionID()) + connectionID := xid.New().String() defer user.CloseFs() //nolint:errcheck if err = user.CheckFsRoot(connectionID); err != nil { @@ -638,7 +639,6 @@ func (c *Configuration) AcceptInboundConnection(conn net.Conn, config *ssh.Serve } channelCounter++ - sshConnection.UpdateLastActivity() // Channels have a type that is dependent on the protocol. For SFTP this is "subsystem" // with a payload that (should) be "sftp". Discard anything else we receive ("pty", "shell", etc) go func(in <-chan *ssh.Request, counter int64) { @@ -650,6 +650,7 @@ func (c *Configuration) AcceptInboundConnection(conn net.Conn, config *ssh.Serve case "subsystem": if bytes.Equal(req.Payload[4:], []byte("sftp")) { ok = true + sshConnection.UpdateLastActivity() connection := &Connection{ BaseConnection: common.NewBaseConnection(connID, common.ProtocolSFTP, conn.LocalAddr().String(), conn.RemoteAddr().String(), user), @@ -671,6 +672,9 @@ func (c *Configuration) AcceptInboundConnection(conn net.Conn, config *ssh.Serve channel: channel, } ok = processSSHCommand(req.Payload, &connection, c.EnabledSSHCommands) + if ok { + sshConnection.UpdateLastActivity() + } } if req.WantReply { req.Reply(ok, nil) //nolint:errcheck diff --git a/sftpgo.json b/sftpgo.json index f77d1afb..2ccca9c2 100644 --- a/sftpgo.json +++ b/sftpgo.json @@ -17,7 +17,6 @@ "startup_hook": "", "post_connect_hook": "", "post_disconnect_hook": "", - "data_retention_hook": "", "max_total_connections": 0, "max_per_host_connections": 20, "allowlist_status": 0,