diff --git a/README.md b/README.md index b282416a..0282865d 100644 --- a/README.md +++ b/README.md @@ -314,7 +314,7 @@ Usage: sftpgo portable [flags] Flags: - -C, --advertise-credentials If the service is advertised via multicast DNS this flag allows to put username/password inside the advertised TXT record + -C, --advertise-credentials If the SFTP service is advertised via multicast DNS this flag allows to put username/password inside the advertised TXT record -S, --advertise-service Advertise SFTP service using multicast DNS (default true) -d, --directory string Path to the directory to serve. This can be an absolute path or a path relative to the current directory (default ".") -h, --help help for portable diff --git a/cmd/portable.go b/cmd/portable.go index cc349220..95c62b76 100644 --- a/cmd/portable.go +++ b/cmd/portable.go @@ -74,6 +74,6 @@ func init() { portableCmd.Flags().BoolVarP(&portableAdvertiseService, "advertise-service", "S", true, "Advertise SFTP service using multicast DNS") portableCmd.Flags().BoolVarP(&portableAdvertiseCredentials, "advertise-credentials", "C", false, - "If the service is advertised via multicast DNS this flag allows to put username/password inside the advertised TXT record") + "If the SFTP service is advertised via multicast DNS this flag allows to put username/password inside the advertised TXT record") rootCmd.AddCommand(portableCmd) } diff --git a/sftpd/handler.go b/sftpd/handler.go index 6e2f9a39..7ea40130 100644 --- a/sftpd/handler.go +++ b/sftpd/handler.go @@ -220,7 +220,9 @@ func (c Connection) Filelist(request *sftp.Request) (sftp.ListerAt, error) { c.Log(logger.LevelDebug, logSender, "requested list file for dir: %#v", p) files, err := ioutil.ReadDir(p) - if err != nil { + if os.IsNotExist(err) { + return nil, sftp.ErrSSHFxNoSuchFile + } else if err != nil { c.Log(logger.LevelError, logSender, "error listing directory: %#v", err) return nil, sftp.ErrSSHFxFailure } diff --git a/sftpd/sftpd_test.go b/sftpd/sftpd_test.go index 2f2d0935..ad758ad5 100644 --- a/sftpd/sftpd_test.go +++ b/sftpd/sftpd_test.go @@ -1227,6 +1227,67 @@ func TestMissingFile(t *testing.T) { os.RemoveAll(user.GetHomeDir()) } +func TestOpenError(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("this test is not available on Windows") + } + usePubKey := false + u := getTestUser(usePubKey) + user, _, err := httpd.AddUser(u, http.StatusOK) + if err != nil { + t.Errorf("unable to add user: %v", err) + } + os.RemoveAll(user.GetHomeDir()) + client, err := getSftpClient(user, usePubKey) + if err != nil { + t.Errorf("unable to create sftp client: %v", err) + } else { + defer client.Close() + os.Chmod(user.GetHomeDir(), 0001) + _, err = client.ReadDir(".") + if err == nil { + t.Errorf("read dir must fail if we have no filesystem read permissions") + } + os.Chmod(user.GetHomeDir(), 0755) + testFileSize := int64(65535) + testFileName := "test_file.dat" + testFilePath := filepath.Join(user.GetHomeDir(), testFileName) + err = createTestFile(testFilePath, testFileSize) + if err != nil { + t.Errorf("unable to create test file: %v", err) + } + _, err = client.Stat(testFileName) + if err != nil { + t.Errorf("file stat error: %v", err) + } + localDownloadPath := filepath.Join(homeBasePath, "test_download.dat") + err = sftpDownloadFile(testFileName, localDownloadPath, testFileSize, client) + if err != nil { + t.Errorf("file download error: %v", err) + } + os.Chmod(testFilePath, 0001) + err = sftpDownloadFile(testFileName, localDownloadPath, testFileSize, client) + if err == nil { + t.Errorf("file download must fail if we have no filesystem read permissions") + } + err = sftpUploadFile(localDownloadPath, testFileName, testFileSize, client) + if err == nil { + t.Errorf("upload must fail if we have no filesystem write permissions") + } + os.Chmod(user.GetHomeDir(), 0000) + _, err = client.Lstat(testFileName) + if err == nil { + t.Errorf("file stat must fail if we have no filesystem read permissions") + } + os.Chmod(user.GetHomeDir(), 0755) + } + _, err = httpd.RemoveUser(user, http.StatusOK) + if err != nil { + t.Errorf("unable to remove user: %v", err) + } + os.RemoveAll(user.GetHomeDir()) +} + func TestOverwriteDirWithFile(t *testing.T) { usePubKey := false u := getTestUser(usePubKey)