From 900e519ff1d96e588a454c2cd735714dce2c171e Mon Sep 17 00:00:00 2001 From: Nicola Murino Date: Wed, 16 Feb 2022 16:05:56 +0100 Subject: [PATCH] SFTP: respect file open flags also for file creation Signed-off-by: Nicola Murino --- common/protocol_test.go | 6 +++--- go.mod | 4 ++-- go.sum | 9 ++++----- sftpd/cryptfs_test.go | 2 +- sftpd/handler.go | 7 ++++--- sftpd/internal_test.go | 2 +- sftpd/sftpd_test.go | 8 ++++---- vfs/osfs.go | 2 +- vfs/sftpfs.go | 3 +++ 9 files changed, 23 insertions(+), 20 deletions(-) diff --git a/common/protocol_test.go b/common/protocol_test.go index 03e6b728..85e81c28 100644 --- a/common/protocol_test.go +++ b/common/protocol_test.go @@ -661,7 +661,7 @@ func TestTruncateQuotaLimits(t *testing.T) { if assert.NoError(t, err) { defer conn.Close() defer client.Close() - f, err := client.OpenFile(testFileName, os.O_WRONLY) + f, err := client.OpenFile(testFileName, os.O_WRONLY|os.O_CREATE) if assert.NoError(t, err) { n, err := f.Write(testFileContent) assert.NoError(t, err) @@ -779,7 +779,7 @@ func TestTruncateQuotaLimits(t *testing.T) { if user.Username == defaultUsername { // basic test inside a virtual folder vfileName1 := path.Join(vdirPath1, testFileName) - f, err = client.OpenFile(vfileName1, os.O_WRONLY) + f, err = client.OpenFile(vfileName1, os.O_WRONLY|os.O_CREATE) if assert.NoError(t, err) { n, err := f.Write(testFileContent) assert.NoError(t, err) @@ -808,7 +808,7 @@ func TestTruncateQuotaLimits(t *testing.T) { assert.Equal(t, 1, fold.UsedQuotaFiles) // now test on vdirPath2, the folder quota is included in the user's quota vfileName2 := path.Join(vdirPath2, testFileName) - f, err = client.OpenFile(vfileName2, os.O_WRONLY) + f, err = client.OpenFile(vfileName2, os.O_WRONLY|os.O_CREATE) if assert.NoError(t, err) { n, err := f.Write(testFileContent) assert.NoError(t, err) diff --git a/go.mod b/go.mod index e5337650..1b639aea 100644 --- a/go.mod +++ b/go.mod @@ -58,7 +58,7 @@ require ( golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 golang.org/x/sys v0.0.0-20220209214540-3681064d5158 golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 - google.golang.org/api v0.68.0 + google.golang.org/api v0.69.0 gopkg.in/natefinch/lumberjack.v2 v2.0.0 ) @@ -127,7 +127,7 @@ require ( golang.org/x/tools v0.1.9 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20220211171837-173942840c17 // indirect + google.golang.org/genproto v0.0.0-20220215190005-e57b466719ef // indirect google.golang.org/grpc v1.44.0 // indirect google.golang.org/protobuf v1.27.1 // indirect gopkg.in/ini.v1 v1.66.4 // indirect diff --git a/go.sum b/go.sum index c36557de..7c167abe 100644 --- a/go.sum +++ b/go.sum @@ -950,7 +950,6 @@ golang.org/x/sys v0.0.0-20220110181412-a018aaa089fe/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220111092808-5a964db01320/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220209214540-3681064d5158 h1:rm+CHSpPEEW2IsXUib1ThaHIjuBVZjxNgSKmBLFfD4c= golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -1085,8 +1084,8 @@ google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tD google.golang.org/api v0.64.0/go.mod h1:931CdxA8Rm4t6zqTFGSsgwbAEZ2+GMYurbndwSimebM= google.golang.org/api v0.66.0/go.mod h1:I1dmXYpX7HGwz/ejRxwQp2qj5bFAz93HiCU1C1oYd9M= google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= -google.golang.org/api v0.68.0 h1:9eJiHhwJKIYX6sX2fUZxQLi7pDRA/MYu8c12q6WbJik= -google.golang.org/api v0.68.0/go.mod h1:sOM8pTpwgflXRhz+oC8H2Dr+UcbMqkPPWNJo88Q7TH8= +google.golang.org/api v0.69.0 h1:yHW5s2SFyDapr/43kYtIQmoaaFVW4baLMLwqV4auj2A= +google.golang.org/api v0.69.0/go.mod h1:boanBiw+h5c3s+tBPgEzLDRHfFLWV0qXxRHz3ws7C80= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1173,10 +1172,10 @@ google.golang.org/genproto v0.0.0-20220111164026-67b88f271998/go.mod h1:5CzLGKJ6 google.golang.org/genproto v0.0.0-20220114231437-d2e6a121cae0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20220201184016-50beb8ab5c44/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220204002441-d6cc3cc0770e/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220211171837-173942840c17 h1:2X+CNIheCutWRyKRte8szGxrE5ggtV4U+NKAbh/oLhg= google.golang.org/genproto v0.0.0-20220211171837-173942840c17/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220215190005-e57b466719ef h1:LgGaJzny+/at3jTXZUNh/l8VBWyAiskCHrwq6iEYE7I= +google.golang.org/genproto v0.0.0-20220215190005-e57b466719ef/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= diff --git a/sftpd/cryptfs_test.go b/sftpd/cryptfs_test.go index 401680e0..22de35f4 100644 --- a/sftpd/cryptfs_test.go +++ b/sftpd/cryptfs_test.go @@ -349,7 +349,7 @@ func TestTruncate(t *testing.T) { if assert.NoError(t, err) { defer conn.Close() defer client.Close() - f, err := client.OpenFile(testFileName, os.O_WRONLY) + f, err := client.OpenFile(testFileName, os.O_WRONLY|os.O_CREATE) if assert.NoError(t, err) { err = f.Truncate(0) assert.NoError(t, err) diff --git a/sftpd/handler.go b/sftpd/handler.go index 90d91f2e..0e5ef0d6 100644 --- a/sftpd/handler.go +++ b/sftpd/handler.go @@ -141,7 +141,7 @@ func (c *Connection) handleFilewrite(request *sftp.Request) (sftp.WriterAtReader if !c.User.HasPerm(dataprovider.PermUpload, path.Dir(request.Filepath)) { return nil, sftp.ErrSSHFxPermissionDenied } - return c.handleSFTPUploadToNewFile(fs, p, filePath, request.Filepath, errForRead) + return c.handleSFTPUploadToNewFile(fs, request.Pflags(), p, filePath, request.Filepath, errForRead) } if statErr != nil { @@ -345,7 +345,7 @@ func (c *Connection) handleSFTPRemove(request *sftp.Request) error { return c.RemoveFile(fs, fsPath, request.Filepath, fi) } -func (c *Connection) handleSFTPUploadToNewFile(fs vfs.Fs, resolvedPath, filePath, requestPath string, errForRead error) (sftp.WriterAtReaderAt, error) { +func (c *Connection) handleSFTPUploadToNewFile(fs vfs.Fs, pflags sftp.FileOpenFlags, resolvedPath, filePath, requestPath string, errForRead error) (sftp.WriterAtReaderAt, error) { diskQuota, transferQuota := c.HasSpace(true, false, requestPath) if !diskQuota.HasSpace || !transferQuota.HasUploadSpace() { c.Log(logger.LevelInfo, "denying file write due to quota limits") @@ -357,7 +357,8 @@ func (c *Connection) handleSFTPUploadToNewFile(fs vfs.Fs, resolvedPath, filePath return nil, c.GetPermissionDeniedError() } - file, w, cancelFn, err := fs.Create(filePath, 0) + osFlags := getOSOpenFlags(pflags) + file, w, cancelFn, err := fs.Create(filePath, osFlags) if err != nil { c.Log(logger.LevelError, "error creating file %#v: %+v", resolvedPath, err) return nil, c.GetFsError(fs, err) diff --git a/sftpd/internal_test.go b/sftpd/internal_test.go index bfa4c521..76e00d32 100644 --- a/sftpd/internal_test.go +++ b/sftpd/internal_test.go @@ -309,7 +309,7 @@ func TestUploadFiles(t *testing.T) { if runtime.GOOS == osWindows { missingFile = "missing\\relative\\file.txt" } - _, err = c.handleSFTPUploadToNewFile(fs, ".", missingFile, "/missing", nil) + _, err = c.handleSFTPUploadToNewFile(fs, flags, ".", missingFile, "/missing", nil) assert.Error(t, err, "upload new file in missing path must fail") fs = newMockOsFs(nil, nil, false, "123", os.TempDir()) diff --git a/sftpd/sftpd_test.go b/sftpd/sftpd_test.go index 5908d356..524d206c 100644 --- a/sftpd/sftpd_test.go +++ b/sftpd/sftpd_test.go @@ -568,12 +568,12 @@ func TestFolderPrefix(t *testing.T) { assert.Equal(t, "files", contents[0].Name()) } } - _, err = client.OpenFile(testFileName, os.O_WRONLY) + _, err = client.OpenFile(testFileName, os.O_WRONLY|os.O_CREATE) assert.ErrorIs(t, err, os.ErrPermission) _, err = client.OpenFile(testFileName, os.O_RDONLY) assert.ErrorIs(t, err, os.ErrPermission) - f, err := client.OpenFile(path.Join("prefix", "files", testFileName), os.O_WRONLY) + f, err := client.OpenFile(path.Join("prefix", "files", testFileName), os.O_WRONLY|os.O_CREATE) assert.NoError(t, err) _, err = f.Write([]byte("test")) assert.NoError(t, err) @@ -4930,7 +4930,7 @@ func TestTruncateQuotaLimits(t *testing.T) { defer conn.Close() defer client.Close() data := []byte("test data") - f, err := client.OpenFile(testFileName, os.O_WRONLY) + f, err := client.OpenFile(testFileName, os.O_WRONLY|os.O_CREATE) if assert.NoError(t, err) { n, err := f.Write(data) assert.NoError(t, err) @@ -5048,7 +5048,7 @@ func TestTruncateQuotaLimits(t *testing.T) { if user.Username == defaultUsername { // basic test inside a virtual folder vfileName := path.Join(vdirPath, testFileName) - f, err = client.OpenFile(vfileName, os.O_WRONLY) + f, err = client.OpenFile(vfileName, os.O_WRONLY|os.O_CREATE) if assert.NoError(t, err) { n, err := f.Write(data) assert.NoError(t, err) diff --git a/vfs/osfs.go b/vfs/osfs.go index 374edd4c..8b0f3a9e 100644 --- a/vfs/osfs.go +++ b/vfs/osfs.go @@ -93,7 +93,7 @@ func (*OsFs) Create(name string, flag int) (File, *PipeWriter, func(), error) { if flag == 0 { f, err = os.Create(name) } else { - f, err = os.OpenFile(name, flag, os.ModePerm) + f, err = os.OpenFile(name, flag, 0666) } return f, nil, nil, err } diff --git a/vfs/sftpfs.go b/vfs/sftpfs.go index ebf1da84..7ce307ce 100644 --- a/vfs/sftpfs.go +++ b/vfs/sftpfs.go @@ -324,6 +324,9 @@ func (fs *SFTPFs) Rename(source, target string) error { if err := fs.checkConnection(); err != nil { return err } + if _, ok := fs.sftpClient.HasExtension("posix-rename@openssh.com"); ok { + return fs.sftpClient.PosixRename(source, target) + } return fs.sftpClient.Rename(source, target) }