From e046b35b97feff72ca6a93edce33eaefc143af3e Mon Sep 17 00:00:00 2001 From: Nicola Murino Date: Sun, 5 Jan 2020 11:41:25 +0100 Subject: [PATCH] check permissions against sftp path instead of building filesystem paths and then checking permissions against path relative to the home dir that is the initial sftp path --- dataprovider/user.go | 18 ++++--- sftpd/handler.go | 108 +++++++++++++++++++++-------------------- sftpd/internal_test.go | 27 ++++++++--- sftpd/scp.go | 28 ++++------- sftpd/sftpd_test.go | 28 +++++------ sftpd/ssh_cmd.go | 6 +-- 6 files changed, 111 insertions(+), 104 deletions(-) diff --git a/dataprovider/user.go b/dataprovider/user.go index 05a6eee5..bd7ee927 100644 --- a/dataprovider/user.go +++ b/dataprovider/user.go @@ -100,7 +100,8 @@ type User struct { Filters UserFilters `json:"filters"` } -// GetPermissionsForPath returns the permissions for the given path +// GetPermissionsForPath returns the permissions for the given path. +// The path must be an SFTP path func (u *User) GetPermissionsForPath(p string) []string { permissions := []string{} if perms, ok := u.Permissions["/"]; ok { @@ -111,17 +112,18 @@ func (u *User) GetPermissionsForPath(p string) []string { // fallback permissions permissions = perms } - relPath := u.GetRelativePath(p) - if len(relPath) == 0 { - relPath = "/" + sftpPath := filepath.ToSlash(p) + if !path.IsAbs(p) { + sftpPath = "/" + sftpPath } - dirsForPath := []string{relPath} + sftpPath = path.Clean(sftpPath) + dirsForPath := []string{sftpPath} for { - if relPath == "/" { + if sftpPath == "/" { break } - relPath = path.Dir(relPath) - dirsForPath = append(dirsForPath, relPath) + sftpPath = path.Dir(sftpPath) + dirsForPath = append(dirsForPath, sftpPath) } // dirsForPath contains all the dirs for a given path in reverse order // for example if the path is: /1/2/3/4 it contains: diff --git a/sftpd/handler.go b/sftpd/handler.go index a72b0ef3..42482536 100644 --- a/sftpd/handler.go +++ b/sftpd/handler.go @@ -6,6 +6,7 @@ import ( "io/ioutil" "net" "os" + "path" "path/filepath" "strings" "sync" @@ -51,13 +52,14 @@ func (c Connection) Log(level logger.LogLevel, sender string, format string, v . func (c Connection) Fileread(request *sftp.Request) (io.ReaderAt, error) { updateConnectionActivity(c.ID) + if !c.User.HasPerm(dataprovider.PermDownload, path.Dir(request.Filepath)) { + return nil, sftp.ErrSSHFxPermissionDenied + } + p, err := c.buildPath(request.Filepath) if err != nil { return nil, getSFTPErrorFromOSError(err) } - if !c.User.HasPerm(dataprovider.PermDownload, filepath.Dir(p)) { - return nil, sftp.ErrSSHFxPermissionDenied - } c.lock.Lock() defer c.lock.Unlock() @@ -112,7 +114,7 @@ func (c Connection) Filewrite(request *sftp.Request) (io.WriterAt, error) { stat, statErr := os.Stat(p) if os.IsNotExist(statErr) { - if !c.User.HasPerm(dataprovider.PermUpload, filepath.Dir(p)) { + if !c.User.HasPerm(dataprovider.PermUpload, path.Dir(request.Filepath)) { return nil, sftp.ErrSSHFxPermissionDenied } return c.handleSFTPUploadToNewFile(p, filePath) @@ -129,7 +131,7 @@ func (c Connection) Filewrite(request *sftp.Request) (io.WriterAt, error) { return nil, sftp.ErrSSHFxOpUnsupported } - if !c.User.HasPerm(dataprovider.PermOverwrite, filepath.Dir(filePath)) { + if !c.User.HasPerm(dataprovider.PermOverwrite, path.Dir(request.Filepath)) { return nil, sftp.ErrSSHFxPermissionDenied } @@ -157,26 +159,26 @@ func (c Connection) Filecmd(request *sftp.Request) error { case "Setstat": return c.handleSFTPSetstat(p, request) case "Rename": - if err = c.handleSFTPRename(p, target); err != nil { + if err = c.handleSFTPRename(p, target, request); err != nil { return err } break case "Rmdir": - return c.handleSFTPRmdir(p) + return c.handleSFTPRmdir(p, request) case "Mkdir": - err = c.handleSFTPMkdir(p) + err = c.handleSFTPMkdir(p, request) if err != nil { return err } break case "Symlink": - if err = c.handleSFTPSymlink(p, target); err != nil { + if err = c.handleSFTPSymlink(p, target, request); err != nil { return err } break case "Remove": - return c.handleSFTPRemove(p) + return c.handleSFTPRemove(p, request) default: return sftp.ErrSSHFxOpUnsupported @@ -204,7 +206,7 @@ func (c Connection) Filelist(request *sftp.Request) (sftp.ListerAt, error) { switch request.Method { case "List": - if !c.User.HasPerm(dataprovider.PermListItems, p) { + if !c.User.HasPerm(dataprovider.PermListItems, request.Filepath) { return nil, sftp.ErrSSHFxPermissionDenied } @@ -218,7 +220,7 @@ func (c Connection) Filelist(request *sftp.Request) (sftp.ListerAt, error) { return listerAt(files), nil case "Stat": - if !c.User.HasPerm(dataprovider.PermListItems, filepath.Dir(p)) { + if !c.User.HasPerm(dataprovider.PermListItems, path.Dir(request.Filepath)) { return nil, sftp.ErrSSHFxPermissionDenied } @@ -249,7 +251,7 @@ func (c Connection) getSFTPCmdTargetPath(requestTarget string) (string, error) { return target, nil } -func (c Connection) handleSFTPSetstat(path string, request *sftp.Request) error { +func (c Connection) handleSFTPSetstat(filePath string, request *sftp.Request) error { if setstatMode == 1 { return nil } @@ -258,10 +260,10 @@ func (c Connection) handleSFTPSetstat(path string, request *sftp.Request) error c.ClientVersion) return sftp.ErrSSHFxBadMessage } - pathForPerms := path - if fi, err := os.Lstat(path); err == nil { + pathForPerms := request.Filepath + if fi, err := os.Lstat(filePath); err == nil { if fi.IsDir() { - pathForPerms = filepath.Dir(path) + pathForPerms = path.Dir(request.Filepath) } } attrFlags := request.AttrFlags() @@ -270,11 +272,11 @@ func (c Connection) handleSFTPSetstat(path string, request *sftp.Request) error return sftp.ErrSSHFxPermissionDenied } fileMode := request.Attributes().FileMode() - if err := os.Chmod(path, fileMode); err != nil { - c.Log(logger.LevelWarn, logSender, "failed to chmod path %#v, mode: %v, err: %v", path, fileMode.String(), err) + if err := os.Chmod(filePath, fileMode); err != nil { + c.Log(logger.LevelWarn, logSender, "failed to chmod path %#v, mode: %v, err: %v", filePath, fileMode.String(), err) return getSFTPErrorFromOSError(err) } - logger.CommandLog(chmodLogSender, path, "", c.User.Username, fileMode.String(), c.ID, c.protocol, -1, -1, "", "", "") + logger.CommandLog(chmodLogSender, filePath, "", c.User.Username, fileMode.String(), c.ID, c.protocol, -1, -1, "", "", "") return nil } else if attrFlags.UidGid { if !c.User.HasPerm(dataprovider.PermChown, pathForPerms) { @@ -282,11 +284,11 @@ func (c Connection) handleSFTPSetstat(path string, request *sftp.Request) error } uid := int(request.Attributes().UID) gid := int(request.Attributes().GID) - if err := os.Chown(path, uid, gid); err != nil { - c.Log(logger.LevelWarn, logSender, "failed to chown path %#v, uid: %v, gid: %v, err: %v", path, uid, gid, err) + if err := os.Chown(filePath, uid, gid); err != nil { + c.Log(logger.LevelWarn, logSender, "failed to chown path %#v, uid: %v, gid: %v, err: %v", filePath, uid, gid, err) return getSFTPErrorFromOSError(err) } - logger.CommandLog(chownLogSender, path, "", c.User.Username, "", c.ID, c.protocol, uid, gid, "", "", "") + logger.CommandLog(chownLogSender, filePath, "", c.User.Username, "", c.ID, c.protocol, uid, gid, "", "", "") return nil } else if attrFlags.Acmodtime { if !c.User.HasPerm(dataprovider.PermChtimes, pathForPerms) { @@ -297,24 +299,24 @@ func (c Connection) handleSFTPSetstat(path string, request *sftp.Request) error modificationTime := time.Unix(int64(request.Attributes().Mtime), 0) accessTimeString := accessTime.Format(dateFormat) modificationTimeString := modificationTime.Format(dateFormat) - if err := os.Chtimes(path, accessTime, modificationTime); err != nil { + if err := os.Chtimes(filePath, accessTime, modificationTime); err != nil { c.Log(logger.LevelWarn, logSender, "failed to chtimes for path %#v, access time: %v, modification time: %v, err: %v", - path, accessTime, modificationTime, err) + filePath, accessTime, modificationTime, err) return getSFTPErrorFromOSError(err) } - logger.CommandLog(chtimesLogSender, path, "", c.User.Username, "", c.ID, c.protocol, -1, -1, accessTimeString, + logger.CommandLog(chtimesLogSender, filePath, "", c.User.Username, "", c.ID, c.protocol, -1, -1, accessTimeString, modificationTimeString, "") return nil } return nil } -func (c Connection) handleSFTPRename(sourcePath string, targetPath string) error { +func (c Connection) handleSFTPRename(sourcePath string, targetPath string, request *sftp.Request) error { if c.User.GetRelativePath(sourcePath) == "/" { c.Log(logger.LevelWarn, logSender, "renaming root dir is not allowed") return sftp.ErrSSHFxPermissionDenied } - if !c.User.HasPerm(dataprovider.PermRename, filepath.Dir(targetPath)) { + if !c.User.HasPerm(dataprovider.PermRename, path.Dir(request.Target)) { return sftp.ErrSSHFxPermissionDenied } if err := os.Rename(sourcePath, targetPath); err != nil { @@ -326,41 +328,41 @@ func (c Connection) handleSFTPRename(sourcePath string, targetPath string) error return nil } -func (c Connection) handleSFTPRmdir(path string) error { - if c.User.GetRelativePath(path) == "/" { +func (c Connection) handleSFTPRmdir(dirPath string, request *sftp.Request) error { + if c.User.GetRelativePath(dirPath) == "/" { c.Log(logger.LevelWarn, logSender, "removing root dir is not allowed") return sftp.ErrSSHFxPermissionDenied } - if !c.User.HasPerm(dataprovider.PermDelete, filepath.Dir(path)) { + if !c.User.HasPerm(dataprovider.PermDelete, path.Dir(request.Filepath)) { return sftp.ErrSSHFxPermissionDenied } var fi os.FileInfo var err error - if fi, err = os.Lstat(path); err != nil { - c.Log(logger.LevelWarn, logSender, "failed to remove a dir %#v: stat error: %v", path, err) + if fi, err = os.Lstat(dirPath); err != nil { + c.Log(logger.LevelWarn, logSender, "failed to remove a dir %#v: stat error: %v", dirPath, err) return getSFTPErrorFromOSError(err) } if !fi.IsDir() || fi.Mode()&os.ModeSymlink == os.ModeSymlink { - c.Log(logger.LevelDebug, logSender, "cannot remove %#v is not a directory", path) + c.Log(logger.LevelDebug, logSender, "cannot remove %#v is not a directory", dirPath) return sftp.ErrSSHFxFailure } - if err = os.Remove(path); err != nil { - c.Log(logger.LevelWarn, logSender, "failed to remove directory %#v: %v", path, err) + if err = os.Remove(dirPath); err != nil { + c.Log(logger.LevelWarn, logSender, "failed to remove directory %#v: %v", dirPath, err) return getSFTPErrorFromOSError(err) } - logger.CommandLog(rmdirLogSender, path, "", c.User.Username, "", c.ID, c.protocol, -1, -1, "", "", "") + logger.CommandLog(rmdirLogSender, dirPath, "", c.User.Username, "", c.ID, c.protocol, -1, -1, "", "", "") return sftp.ErrSSHFxOk } -func (c Connection) handleSFTPSymlink(sourcePath string, targetPath string) error { +func (c Connection) handleSFTPSymlink(sourcePath string, targetPath string, request *sftp.Request) error { if c.User.GetRelativePath(sourcePath) == "/" { c.Log(logger.LevelWarn, logSender, "symlinking root dir is not allowed") return sftp.ErrSSHFxPermissionDenied } - if !c.User.HasPerm(dataprovider.PermCreateSymlinks, filepath.Dir(targetPath)) { + if !c.User.HasPerm(dataprovider.PermCreateSymlinks, path.Dir(request.Target)) { return sftp.ErrSSHFxPermissionDenied } if err := os.Symlink(sourcePath, targetPath); err != nil { @@ -372,47 +374,47 @@ func (c Connection) handleSFTPSymlink(sourcePath string, targetPath string) erro return nil } -func (c Connection) handleSFTPMkdir(path string) error { - if !c.User.HasPerm(dataprovider.PermCreateDirs, filepath.Dir(path)) { +func (c Connection) handleSFTPMkdir(dirPath string, request *sftp.Request) error { + if !c.User.HasPerm(dataprovider.PermCreateDirs, path.Dir(request.Filepath)) { return sftp.ErrSSHFxPermissionDenied } - if err := os.Mkdir(path, 0777); err != nil { - c.Log(logger.LevelWarn, logSender, "error creating missing dir: %#v error: %v", path, err) + if err := os.Mkdir(dirPath, 0777); err != nil { + c.Log(logger.LevelWarn, logSender, "error creating missing dir: %#v error: %v", dirPath, err) return getSFTPErrorFromOSError(err) } - utils.SetPathPermissions(path, c.User.GetUID(), c.User.GetGID()) + utils.SetPathPermissions(dirPath, c.User.GetUID(), c.User.GetGID()) - logger.CommandLog(mkdirLogSender, path, "", c.User.Username, "", c.ID, c.protocol, -1, -1, "", "", "") + logger.CommandLog(mkdirLogSender, dirPath, "", c.User.Username, "", c.ID, c.protocol, -1, -1, "", "", "") return nil } -func (c Connection) handleSFTPRemove(path string) error { - if !c.User.HasPerm(dataprovider.PermDelete, filepath.Dir(path)) { +func (c Connection) handleSFTPRemove(filePath string, request *sftp.Request) error { + if !c.User.HasPerm(dataprovider.PermDelete, path.Dir(request.Filepath)) { return sftp.ErrSSHFxPermissionDenied } var size int64 var fi os.FileInfo var err error - if fi, err = os.Lstat(path); err != nil { - c.Log(logger.LevelWarn, logSender, "failed to remove a file %#v: stat error: %v", path, err) + if fi, err = os.Lstat(filePath); err != nil { + c.Log(logger.LevelWarn, logSender, "failed to remove a file %#v: stat error: %v", filePath, err) return getSFTPErrorFromOSError(err) } if fi.IsDir() && fi.Mode()&os.ModeSymlink != os.ModeSymlink { - c.Log(logger.LevelDebug, logSender, "cannot remove %#v is not a file/symlink", path) + c.Log(logger.LevelDebug, logSender, "cannot remove %#v is not a file/symlink", filePath) return sftp.ErrSSHFxFailure } size = fi.Size() - if err := os.Remove(path); err != nil { - c.Log(logger.LevelWarn, logSender, "failed to remove a file/symlink %#v: %v", path, err) + if err := os.Remove(filePath); err != nil { + c.Log(logger.LevelWarn, logSender, "failed to remove a file/symlink %#v: %v", filePath, err) return getSFTPErrorFromOSError(err) } - logger.CommandLog(removeLogSender, path, "", c.User.Username, "", c.ID, c.protocol, -1, -1, "", "", "") + logger.CommandLog(removeLogSender, filePath, "", c.User.Username, "", c.ID, c.protocol, -1, -1, "", "", "") if fi.Mode()&os.ModeSymlink != os.ModeSymlink { dataprovider.UpdateUserQuota(dataProvider, c.User, -1, -size, false) } - go executeAction(operationDelete, c.User.Username, path, "", "") + go executeAction(operationDelete, c.User.Username, filePath, "", "") return sftp.ErrSSHFxOk } diff --git a/sftpd/internal_test.go b/sftpd/internal_test.go index 165f3fa4..1b1d2dc5 100644 --- a/sftpd/internal_test.go +++ b/sftpd/internal_test.go @@ -310,6 +310,26 @@ func TestSSHCommandPath(t *testing.T) { if path != "/" { t.Errorf("unexpected path: %v", path) } + sshCommand.args = []string{"-t", "."} + path = sshCommand.getDestPath() + if path != "/" { + t.Errorf("unexpected path: %v", path) + } + sshCommand.args = []string{"-t", "//"} + path = sshCommand.getDestPath() + if path != "/" { + t.Errorf("unexpected path: %v", path) + } + sshCommand.args = []string{"-t", "../.."} + path = sshCommand.getDestPath() + if path != "/" { + t.Errorf("unexpected path: %v", path) + } + sshCommand.args = []string{"-t", "/.."} + path = sshCommand.getDestPath() + if path != "/" { + t.Errorf("unexpected path: %v", path) + } } func TestSSHCommandErrors(t *testing.T) { @@ -636,13 +656,6 @@ func TestSCPFileMode(t *testing.T) { } } -func TestSCPGetNonExistingDirContent(t *testing.T) { - _, err := getDirContents("non_existing") - if err == nil { - t.Errorf("get non existing dir contents must fail") - } -} - func TestSCPParseUploadMessage(t *testing.T) { buf := make([]byte, 65535) stdErrBuf := make([]byte, 65535) diff --git a/sftpd/scp.go b/sftpd/scp.go index 7d9f624f..4b9e3a50 100644 --- a/sftpd/scp.go +++ b/sftpd/scp.go @@ -3,6 +3,7 @@ package sftpd import ( "fmt" "io" + "io/ioutil" "math" "os" "path" @@ -83,7 +84,7 @@ func (c *scpCommand) handleRecursiveUpload() error { } } else { // the destination dir is now the parent directory - destPath = filepath.Join(destPath, "..") + destPath = path.Join(destPath, "..") } } else { sizeToRead, name, err := c.parseUploadMessage(command) @@ -120,7 +121,7 @@ func (c *scpCommand) handleCreateDir(dirPath string) error { c.sendErrorMessage(err.Error()) return err } - if !c.connection.User.HasPerm(dataprovider.PermCreateDirs, filepath.Dir(p)) { + if !c.connection.User.HasPerm(dataprovider.PermCreateDirs, path.Dir(dirPath)) { err := fmt.Errorf("Permission denied") c.connection.Log(logger.LevelWarn, logSenderSCP, "error creating dir: %#v, permission denied", dirPath) c.sendErrorMessage(err.Error()) @@ -234,7 +235,7 @@ func (c *scpCommand) handleUpload(uploadFilePath string, sizeToRead int64) error } stat, statErr := os.Stat(p) if os.IsNotExist(statErr) { - if !c.connection.User.HasPerm(dataprovider.PermUpload, filepath.Dir(p)) { + if !c.connection.User.HasPerm(dataprovider.PermUpload, path.Dir(uploadFilePath)) { err := fmt.Errorf("Permission denied") c.connection.Log(logger.LevelWarn, logSenderSCP, "cannot upload file: %#v, permission denied", uploadFilePath) c.sendErrorMessage(err.Error()) @@ -256,7 +257,7 @@ func (c *scpCommand) handleUpload(uploadFilePath string, sizeToRead int64) error return err } - if !c.connection.User.HasPerm(dataprovider.PermOverwrite, filePath) { + if !c.connection.User.HasPerm(dataprovider.PermOverwrite, uploadFilePath) { err := fmt.Errorf("Permission denied") c.connection.Log(logger.LevelWarn, logSenderSCP, "cannot overwrite file: %#v, permission denied", uploadFilePath) c.sendErrorMessage(err.Error()) @@ -302,7 +303,7 @@ func (c *scpCommand) sendDownloadProtocolMessages(dirPath string, stat os.FileIn return err } -// we send first all the files in the roor directory and then the directories +// we send first all the files in the root directory and then the directories // for each directory we recursively call this method again func (c *scpCommand) handleRecursiveDownload(dirPath string, stat os.FileInfo) error { var err error @@ -312,7 +313,7 @@ func (c *scpCommand) handleRecursiveDownload(dirPath string, stat os.FileInfo) e if err != nil { return err } - files, err := getDirContents(dirPath) + files, err := ioutil.ReadDir(dirPath) if err != nil { c.sendErrorMessage(err.Error()) return err @@ -431,7 +432,7 @@ func (c *scpCommand) handleDownload(filePath string) error { } if stat.IsDir() { - if !c.connection.User.HasPerm(dataprovider.PermDownload, p) { + if !c.connection.User.HasPerm(dataprovider.PermDownload, filePath) { err := fmt.Errorf("Permission denied") c.connection.Log(logger.LevelWarn, logSenderSCP, "error downloading dir: %#v, permission denied", filePath) c.sendErrorMessage(err.Error()) @@ -441,7 +442,7 @@ func (c *scpCommand) handleDownload(filePath string) error { return err } - if !c.connection.User.HasPerm(dataprovider.PermDownload, filepath.Dir(p)) { + if !c.connection.User.HasPerm(dataprovider.PermDownload, path.Dir(filePath)) { err := fmt.Errorf("Permission denied") c.connection.Log(logger.LevelWarn, logSenderSCP, "error downloading dir: %#v, permission denied", filePath) c.sendErrorMessage(err.Error()) @@ -732,14 +733,3 @@ func getFileModeAsString(fileMode os.FileMode, isDir bool) string { } return fmt.Sprintf("%v%v%v%v", s, u, g, o) } - -func getDirContents(path string) ([]os.FileInfo, error) { - var files []os.FileInfo - f, err := os.Open(path) - if err != nil { - return files, err - } - files, err = f.Readdir(-1) - f.Close() - return files, err -} diff --git a/sftpd/sftpd_test.go b/sftpd/sftpd_test.go index 20555ad5..9505b26d 100644 --- a/sftpd/sftpd_test.go +++ b/sftpd/sftpd_test.go @@ -2589,48 +2589,48 @@ func TestUserPerms(t *testing.T) { user.Permissions["/p/3"] = []string{dataprovider.PermChmod} user.Permissions["/p/3/4"] = []string{dataprovider.PermChtimes} user.Permissions["/tmp"] = []string{dataprovider.PermRename} - if !user.HasPerm(dataprovider.PermListItems, filepath.Join(user.HomeDir, "/")) { + if !user.HasPerm(dataprovider.PermListItems, "/") { t.Error("expected permission not found") } - if !user.HasPerm(dataprovider.PermListItems, filepath.Join(user.HomeDir, ".")) { + if !user.HasPerm(dataprovider.PermListItems, ".") { t.Error("expected permission not found") } - if !user.HasPerm(dataprovider.PermListItems, filepath.Join(user.HomeDir, "")) { + if !user.HasPerm(dataprovider.PermListItems, "") { t.Error("expected permission not found") } - if !user.HasPerm(dataprovider.PermListItems, filepath.Join(user.HomeDir, "../")) { + if !user.HasPerm(dataprovider.PermListItems, "../") { t.Error("expected permission not found") } // path p and /p are the same - if !user.HasPerm(dataprovider.PermDelete, filepath.Join(user.HomeDir, "/p")) { + if !user.HasPerm(dataprovider.PermDelete, "/p") { t.Error("expected permission not found") } - if !user.HasPerm(dataprovider.PermDownload, filepath.Join(user.HomeDir, "/p/1")) { + if !user.HasPerm(dataprovider.PermDownload, "/p/1") { t.Error("expected permission not found") } - if !user.HasPerm(dataprovider.PermCreateDirs, filepath.Join(user.HomeDir, "p/2")) { + if !user.HasPerm(dataprovider.PermCreateDirs, "p/2") { t.Error("expected permission not found") } - if !user.HasPerm(dataprovider.PermChmod, filepath.Join(user.HomeDir, "/p/3")) { + if !user.HasPerm(dataprovider.PermChmod, "/p/3") { t.Error("expected permission not found") } - if !user.HasPerm(dataprovider.PermChtimes, filepath.Join(user.HomeDir, "p/3/4")) { + if !user.HasPerm(dataprovider.PermChtimes, "p/3/4/") { t.Error("expected permission not found") } - if !user.HasPerm(dataprovider.PermChtimes, filepath.Join(user.HomeDir, "p/3/4/../4")) { + if !user.HasPerm(dataprovider.PermChtimes, "p/3/4/../4") { t.Error("expected permission not found") } // undefined paths have permissions of the nearest path - if !user.HasPerm(dataprovider.PermListItems, filepath.Join(user.HomeDir, "/p34")) { + if !user.HasPerm(dataprovider.PermListItems, "/p34") { t.Error("expected permission not found") } - if !user.HasPerm(dataprovider.PermListItems, filepath.Join(user.HomeDir, "/p34/p1/file.dat")) { + if !user.HasPerm(dataprovider.PermListItems, "/p34/p1/file.dat") { t.Error("expected permission not found") } - if !user.HasPerm(dataprovider.PermChtimes, filepath.Join(user.HomeDir, "/p/3/4/5/6")) { + if !user.HasPerm(dataprovider.PermChtimes, "/p/3/4/5/6") { t.Error("expected permission not found") } - if !user.HasPerm(dataprovider.PermDownload, filepath.Join(user.HomeDir, "/p/1/test/file.dat")) { + if !user.HasPerm(dataprovider.PermDownload, "/p/1/test/file.dat") { t.Error("expected permission not found") } } diff --git a/sftpd/ssh_cmd.go b/sftpd/ssh_cmd.go index c9714a14..08933987 100644 --- a/sftpd/ssh_cmd.go +++ b/sftpd/ssh_cmd.go @@ -129,7 +129,7 @@ func (c *sshCommand) handleHashCommands() error { if err != nil { return c.sendErrorResponse(err) } - if !c.connection.User.HasPerm(dataprovider.PermListItems, path) { + if !c.connection.User.HasPerm(dataprovider.PermListItems, sshPath) { return c.sendErrorResponse(errPermissionDenied) } hash, err := computeHashForFile(h, path) @@ -149,7 +149,7 @@ func (c *sshCommand) executeSystemCommand(command systemCommand) error { } perms := []string{dataprovider.PermDownload, dataprovider.PermUpload, dataprovider.PermCreateDirs, dataprovider.PermListItems, dataprovider.PermOverwrite, dataprovider.PermDelete, dataprovider.PermRename} - if !c.connection.User.HasPerms(perms, command.realPath) { + if !c.connection.User.HasPerms(perms, c.getDestPath()) { return c.sendErrorResponse(errPermissionDenied) } @@ -299,7 +299,7 @@ func (c *sshCommand) getSystemCommand() (systemCommand, error) { // the home dir. // If the user cannot create symlinks we add the option --munge-links, if it is not // already set. This should make symlinks unusable (but manually recoverable) - if c.connection.User.HasPerm(dataprovider.PermCreateSymlinks, path) { + if c.connection.User.HasPerm(dataprovider.PermCreateSymlinks, c.getDestPath()) { if !utils.IsStringInSlice("--safe-links", args) { args = append([]string{"--safe-links"}, args...) }