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
This commit is contained in:
parent
eb2ddc4798
commit
e046b35b97
6 changed files with 111 additions and 104 deletions
|
@ -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:
|
||||
|
|
108
sftpd/handler.go
108
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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
28
sftpd/scp.go
28
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
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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...)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue