diff --git a/go.mod b/go.mod index 90cceb9e..db85fb70 100644 --- a/go.mod +++ b/go.mod @@ -82,7 +82,7 @@ require ( cloud.google.com/go/auth v0.3.0 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.2 // indirect cloud.google.com/go/compute/metadata v0.3.0 // indirect - cloud.google.com/go/iam v1.1.7 // indirect + cloud.google.com/go/iam v1.1.8 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.6.0 // indirect github.com/ajg/form v1.5.1 // indirect @@ -143,7 +143,7 @@ require ( github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/oklog/run v1.1.0 // indirect - github.com/pelletier/go-toml/v2 v2.2.1 // indirect + github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect github.com/prometheus/client_model v0.6.1 // indirect @@ -183,7 +183,7 @@ require ( ) replace ( - github.com/fclairamb/ftpserverlib => github.com/drakkan/ftpserverlib v0.0.0-20240430171908-06190249a088 + github.com/fclairamb/ftpserverlib => github.com/drakkan/ftpserverlib v0.0.0-20240502162317-7bc57ede068a github.com/jlaffaye/ftp => github.com/drakkan/ftp v0.0.0-20240430173938-7ba8270c8e7f github.com/robfig/cron/v3 => github.com/drakkan/cron/v3 v3.0.0-20230222140221-217a1e4d96c0 golang.org/x/crypto => github.com/drakkan/crypto v0.0.0-20240405104909-a6b14455cac6 diff --git a/go.sum b/go.sum index 4e566bb2..64b42c91 100644 --- a/go.sum +++ b/go.sum @@ -9,6 +9,8 @@ cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2Qx cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= cloud.google.com/go/iam v1.1.7 h1:z4VHOhwKLF/+UYXAJDFwGtNF0b6gjsW1Pk9Ml0U/IoM= cloud.google.com/go/iam v1.1.7/go.mod h1:J4PMPg8TtyurAUvSmPj8FF3EDgY1SPRZxcUGrn7WXGA= +cloud.google.com/go/iam v1.1.8 h1:r7umDwhj+BQyz0ScZMp4QrGXjSTI3ZINnpgU2nlB/K0= +cloud.google.com/go/iam v1.1.8/go.mod h1:GvE6lyMmfxXauzNq8NbgJbeVQNspG+tcdL/W8QO1+zE= cloud.google.com/go/kms v1.15.8 h1:szIeDCowID8th2i8XE4uRev5PMxQFqW+JjwYxL9h6xs= cloud.google.com/go/kms v1.15.8/go.mod h1:WoUHcDjD9pluCg7pNds131awnH429QGvRM3N/4MyoVs= cloud.google.com/go/storage v1.40.0 h1:VEpDQV5CJxFmJ6ueWNsKxcr1QAYOXEgxDa+sBbJahPw= @@ -118,8 +120,8 @@ github.com/drakkan/crypto v0.0.0-20240405104909-a6b14455cac6 h1:XzaQu+jRDZWu+Cro github.com/drakkan/crypto v0.0.0-20240405104909-a6b14455cac6/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= github.com/drakkan/ftp v0.0.0-20240430173938-7ba8270c8e7f h1:S9JUlrOzjK58UKoLqqb40YLyVlt0bcIFtYrvnanV3zc= github.com/drakkan/ftp v0.0.0-20240430173938-7ba8270c8e7f/go.mod h1:4p8lUl4vQ80L598CygL+3IFtm+3nggvvW/palOlViwE= -github.com/drakkan/ftpserverlib v0.0.0-20240430171908-06190249a088 h1:M7X8bstrPumVbmxdtHxQMJghiYhFzk/y+LvmWJkihqw= -github.com/drakkan/ftpserverlib v0.0.0-20240430171908-06190249a088/go.mod h1:+9afJRWESpCq4/O8Vr00Q2jfinRxP6PiCpXph6CgGuc= +github.com/drakkan/ftpserverlib v0.0.0-20240502162317-7bc57ede068a h1:IULpJkoPn+DlpbF0owSZDao1yCFuOaDrSnIEpvdxXM8= +github.com/drakkan/ftpserverlib v0.0.0-20240502162317-7bc57ede068a/go.mod h1:+9afJRWESpCq4/O8Vr00Q2jfinRxP6PiCpXph6CgGuc= github.com/drakkan/webdav v0.0.0-20240414072657-7c19d3cb5103 h1:jhcR8ixhpd3f8iBeH/6pJ9V3BNjY3Yjrb7Ipp8Cezmw= github.com/drakkan/webdav v0.0.0-20240414072657-7c19d3cb5103/go.mod h1:zOVb1QDhwwqWn2L2qZ0U3swMSO4GTSNyIwXCGO/UGWE= github.com/eikenb/pipeat v0.0.0-20210730190139-06b3e6902001 h1:/ZshrfQzayqRSBDodmp3rhNCHJCff+utvgBuWRbiqu4= @@ -307,6 +309,8 @@ github.com/otiai10/mint v1.5.1 h1:XaPLeE+9vGbuyEHem1JNk3bYc7KKqyI/na0/mLd/Kks= github.com/otiai10/mint v1.5.1/go.mod h1:MJm72SBthJjz8qhefc4z1PYEieWmy8Bku7CjcAqyUSM= github.com/pelletier/go-toml/v2 v2.2.1 h1:9TA9+T8+8CUCO2+WYnDLCgrYi9+omqKXyjDtosvtEhg= github.com/pelletier/go-toml/v2 v2.2.1/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= +github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= +github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/pires/go-proxyproto v0.7.0 h1:IukmRewDQFWC7kfnb66CSomk2q/seBuilHBYFwyq0Hs= github.com/pires/go-proxyproto v0.7.0/go.mod h1:Vz/1JPY/OACxWGQNIRY2BeyDmpoaWmEP40O9LbuiFR4= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= @@ -421,6 +425,7 @@ go.opentelemetry.io/otel/metric v1.26.0 h1:7S39CLuY5Jgg9CrnA9HHiEjGMF/X2VHvoXGgS go.opentelemetry.io/otel/metric v1.26.0/go.mod h1:SY+rHOI4cEawI9a7N1A4nIg/nTQXe1ccCNWYOJUrpX4= go.opentelemetry.io/otel/sdk v1.22.0 h1:6coWHw9xw7EfClIC/+O31R8IY3/+EiRFHevmHafB2Gw= go.opentelemetry.io/otel/sdk v1.22.0/go.mod h1:iu7luyVGYovrRpe2fmj3CVKouQNdTOkxtLzPvPz1DOc= +go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= go.opentelemetry.io/otel/trace v1.26.0 h1:1ieeAUb4y0TE26jUFrCIXKpTuVK7uJGN9/Z/2LP5sQA= go.opentelemetry.io/otel/trace v1.26.0/go.mod h1:4iDxvGDQuUkHve82hJJ8UqrwswHYsZuWCBllGV2U2y0= go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8= diff --git a/internal/config/config.go b/internal/config/config.go index 6207bdd5..97a0da7b 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -1193,6 +1193,12 @@ func getFTPDBindingSecurityFromEnv(idx int, binding *ftpd.Binding) bool { isSet = true } + ignoreASCIITransferType, ok := lookupIntFromEnv(fmt.Sprintf("SFTPGO_FTPD__BINDINGS__%d__IGNORE_ASCII_TRANSFER_TYPE", idx), 0) + if ok { + binding.IgnoreASCIITransferType = int(ignoreASCIITransferType) + isSet = true + } + return isSet } diff --git a/internal/config/config_test.go b/internal/config/config_test.go index b5a29d79..17fc4702 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -926,6 +926,7 @@ func TestFTPDBindingsFromEnv(t *testing.T) { os.Setenv("SFTPGO_FTPD__BINDINGS__9__CLIENT_AUTH_TYPE", "2") os.Setenv("SFTPGO_FTPD__BINDINGS__9__DEBUG", "1") os.Setenv("SFTPGO_FTPD__BINDINGS__9__ACTIVE_CONNECTIONS_SECURITY", "1") + os.Setenv("SFTPGO_FTPD__BINDINGS__9__IGNORE_ASCII_TRANSFER_TYPE", "1") os.Setenv("SFTPGO_FTPD__BINDINGS__9__CERTIFICATE_FILE", "cert.crt") os.Setenv("SFTPGO_FTPD__BINDINGS__9__CERTIFICATE_KEY_FILE", "cert.key") @@ -950,6 +951,7 @@ func TestFTPDBindingsFromEnv(t *testing.T) { os.Unsetenv("SFTPGO_FTPD__BINDINGS__9__CLIENT_AUTH_TYPE") os.Unsetenv("SFTPGO_FTPD__BINDINGS__9__DEBUG") os.Unsetenv("SFTPGO_FTPD__BINDINGS__9__ACTIVE_CONNECTIONS_SECURITY") + os.Unsetenv("SFTPGO_FTPD__BINDINGS__9__IGNORE_ASCII_TRANSFER_TYPE") os.Unsetenv("SFTPGO_FTPD__BINDINGS__9__CERTIFICATE_FILE") os.Unsetenv("SFTPGO_FTPD__BINDINGS__9__CERTIFICATE_KEY_FILE") }) @@ -974,6 +976,7 @@ func TestFTPDBindingsFromEnv(t *testing.T) { require.False(t, bindings[0].Debug) require.Equal(t, 1, bindings[0].PassiveConnectionsSecurity) require.Equal(t, 0, bindings[0].ActiveConnectionsSecurity) + require.Equal(t, 0, bindings[0].IgnoreASCIITransferType) require.Equal(t, 2203, bindings[1].Port) require.Equal(t, "127.0.1.1", bindings[1].Address) require.True(t, bindings[1].ApplyProxyConfig) // default value @@ -991,6 +994,7 @@ func TestFTPDBindingsFromEnv(t *testing.T) { require.Nil(t, bindings[1].TLSCipherSuites) require.Equal(t, 0, bindings[1].PassiveConnectionsSecurity) require.Equal(t, 1, bindings[1].ActiveConnectionsSecurity) + require.Equal(t, 1, bindings[1].IgnoreASCIITransferType) require.True(t, bindings[1].Debug) require.Equal(t, "cert.crt", bindings[1].CertificateFile) require.Equal(t, "cert.key", bindings[1].CertificateKeyFile) diff --git a/internal/ftpd/ftpd.go b/internal/ftpd/ftpd.go index 3a8cc80b..80dd1531 100644 --- a/internal/ftpd/ftpd.go +++ b/internal/ftpd/ftpd.go @@ -109,6 +109,11 @@ type Binding struct { // Please note that disabling the security checks you will make the FTP service vulnerable to bounce attacks // on active data connections, so change the default value only if you are on a trusted/internal network ActiveConnectionsSecurity int `json:"active_connections_security" mapstructure:"active_connections_security"` + // Set to 1 to silently ignore any client requests to perform ASCII translations via the TYPE command. + // That is, FTP clients can request ASCII translations, and SFTPGo will respond as the client expects, + // but will not actually perform the translation for either uploads or downloads. This behavior can be + // useful in circumstances involving older/mainframe clients and EBCDIC files. + IgnoreASCIITransferType int `json:"ignore_ascii_transfer_type" mapstructure:"ignore_ascii_transfer_type"` // Debug enables the FTP debug mode. In debug mode, every FTP command will be logged Debug bool `json:"debug" mapstructure:"debug"` ciphers []uint16 diff --git a/internal/ftpd/server.go b/internal/ftpd/server.go index 122dfc33..2b5cfd7d 100644 --- a/internal/ftpd/server.go +++ b/internal/ftpd/server.go @@ -133,6 +133,7 @@ func (s *Server) GetSettings() (*ftpserver.Settings, error) { EnableHASH: s.config.HASHSupport > 0, EnableCOMB: s.config.CombineSupport > 0, DefaultTransferType: ftpserver.TransferTypeBinary, + IgnoreASCIITranferType: s.binding.IgnoreASCIITransferType == 1, ActiveConnectionsCheck: ftpserver.DataConnectionRequirement(s.binding.ActiveConnectionsSecurity), PasvConnectionsCheck: ftpserver.DataConnectionRequirement(s.binding.PassiveConnectionsSecurity), }, nil diff --git a/openapi/openapi.yaml b/openapi/openapi.yaml index 3e683555..a52f61d2 100644 --- a/openapi/openapi.yaml +++ b/openapi/openapi.yaml @@ -6446,6 +6446,15 @@ components: Active connections security: * `0` - require matching peer IP addresses of control and data connection * `1` - disable any checks + ignore_ascii_transfer_type: + type: integer + enum: + - 0 + - 1 + description: | + Ignore client requests to perform ASCII translations: + * `0` - ASCII translations are enabled + * `1` - ASCII translations are silently ignored debug: type: boolean description: 'If enabled any FTP command will be logged' diff --git a/sftpgo.json b/sftpgo.json index 7748c3d3..55d17315 100644 --- a/sftpgo.json +++ b/sftpgo.json @@ -126,6 +126,7 @@ "tls_cipher_suites": [], "passive_connections_security": 0, "active_connections_security": 0, + "ignore_ascii_transfer_type": 0, "debug": false } ],