add hide policy to pattern filters

Disallowed files/dirs can be completly hidden. This may cause performance
issues for large directories

Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
This commit is contained in:
Nicola Murino
2022-01-15 17:16:49 +01:00
parent 9b6b9cca3d
commit c3831de94e
20 changed files with 358 additions and 139 deletions

View File

@@ -242,7 +242,7 @@ func (c *BaseConnection) ListDir(virtualPath string) ([]os.FileInfo, error) {
c.Log(logger.LevelDebug, "error listing directory: %+v", err)
return nil, c.GetFsError(fs, err)
}
return c.User.AddVirtualDirs(files, virtualPath), nil
return c.User.FilterListDir(files, virtualPath), nil
}
// CheckParentDirs tries to create the specified directory and any missing parent dirs
@@ -254,7 +254,7 @@ func (c *BaseConnection) CheckParentDirs(virtualPath string) error {
if fs.HasVirtualFolders() {
return nil
}
if _, err := c.DoStat(virtualPath, 0); !c.IsNotExistError(err) {
if _, err := c.DoStat(virtualPath, 0, false); !c.IsNotExistError(err) {
return err
}
dirs := util.GetDirsForVirtualPath(virtualPath)
@@ -275,10 +275,15 @@ func (c *BaseConnection) CheckParentDirs(virtualPath string) error {
}
// CreateDir creates a new directory at the specified fsPath
func (c *BaseConnection) CreateDir(virtualPath string) error {
func (c *BaseConnection) CreateDir(virtualPath string, checkFilePatterns bool) error {
if !c.User.HasPerm(dataprovider.PermCreateDirs, path.Dir(virtualPath)) {
return c.GetPermissionDeniedError()
}
if checkFilePatterns {
if ok, _ := c.User.IsFileAllowed(virtualPath); !ok {
return c.GetPermissionDeniedError()
}
}
if c.User.IsVirtualFolder(virtualPath) {
c.Log(logger.LevelWarn, "mkdir not allowed %#v is a virtual folder", virtualPath)
return c.GetPermissionDeniedError()
@@ -304,9 +309,9 @@ func (c *BaseConnection) IsRemoveFileAllowed(virtualPath string) error {
if !c.User.HasAnyPerm([]string{dataprovider.PermDeleteFiles, dataprovider.PermDelete}, path.Dir(virtualPath)) {
return c.GetPermissionDeniedError()
}
if !c.User.IsFileAllowed(virtualPath) {
if ok, policy := c.User.IsFileAllowed(virtualPath); !ok {
c.Log(logger.LevelDebug, "removing file %#v is not allowed", virtualPath)
return c.GetPermissionDeniedError()
return c.GetErrorForDeniedFile(policy)
}
return nil
}
@@ -368,6 +373,10 @@ func (c *BaseConnection) IsRemoveDirAllowed(fs vfs.Fs, fsPath, virtualPath strin
if !c.User.HasAnyPerm([]string{dataprovider.PermDeleteDirs, dataprovider.PermDelete}, path.Dir(virtualPath)) {
return c.GetPermissionDeniedError()
}
if ok, policy := c.User.IsFileAllowed(virtualPath); !ok {
c.Log(logger.LevelDebug, "removing directory %#v is not allowed", virtualPath)
return c.GetErrorForDeniedFile(policy)
}
return nil
}
@@ -488,16 +497,25 @@ func (c *BaseConnection) CreateSymlink(virtualSourcePath, virtualTargetPath stri
return c.GetFsError(fs, err)
}
if fs.GetRelativePath(fsSourcePath) == "/" {
c.Log(logger.LevelWarn, "symlinking root dir is not allowed")
c.Log(logger.LevelError, "symlinking root dir is not allowed")
return c.GetPermissionDeniedError()
}
if fs.GetRelativePath(fsTargetPath) == "/" {
c.Log(logger.LevelWarn, "symlinking to root dir is not allowed")
c.Log(logger.LevelError, "symlinking to root dir is not allowed")
return c.GetPermissionDeniedError()
}
if !c.User.HasPerm(dataprovider.PermCreateSymlinks, path.Dir(virtualTargetPath)) {
return c.GetPermissionDeniedError()
}
ok, policy := c.User.IsFileAllowed(virtualSourcePath)
if !ok && policy == sdk.DenyPolicyHide {
c.Log(logger.LevelError, "symlink source path %#v is not allowed", virtualSourcePath)
return c.GetNotExistError()
}
if ok, _ = c.User.IsFileAllowed(virtualTargetPath); !ok {
c.Log(logger.LevelError, "symlink target path %#v is not allowed", virtualTargetPath)
return c.GetPermissionDeniedError()
}
if err := fs.Symlink(fsSourcePath, fsTargetPath); err != nil {
c.Log(logger.LevelError, "failed to create symlink %#v -> %#v: %+v", fsSourcePath, fsTargetPath, err)
return c.GetFsError(fs, err)
@@ -518,13 +536,19 @@ func (c *BaseConnection) getPathForSetStatPerms(fs vfs.Fs, fsPath, virtualPath s
}
// DoStat execute a Stat if mode = 0, Lstat if mode = 1
func (c *BaseConnection) DoStat(virtualPath string, mode int) (os.FileInfo, error) {
func (c *BaseConnection) DoStat(virtualPath string, mode int, checkFilePatterns bool) (os.FileInfo, error) {
// for some vfs we don't create intermediary folders so we cannot simply check
// if virtualPath is a virtual folder
vfolders := c.User.GetVirtualFoldersInPath(path.Dir(virtualPath))
if _, ok := vfolders[virtualPath]; ok {
return vfs.NewFileInfo(virtualPath, true, 0, time.Now(), false), nil
}
if checkFilePatterns {
ok, policy := c.User.IsFileAllowed(virtualPath)
if !ok && policy == sdk.DenyPolicyHide {
return nil, c.GetNotExistError()
}
}
var info os.FileInfo
@@ -549,9 +573,9 @@ func (c *BaseConnection) DoStat(virtualPath string, mode int) (os.FileInfo, erro
}
func (c *BaseConnection) createDirIfMissing(name string) error {
_, err := c.DoStat(name, 0)
_, err := c.DoStat(name, 0, false)
if c.IsNotExistError(err) {
return c.CreateDir(name)
return c.CreateDir(name, false)
}
return err
}
@@ -625,6 +649,9 @@ func (c *BaseConnection) handleChtimes(fs vfs.Fs, fsPath, pathForPerms string, a
// SetStat set StatAttributes for the specified fsPath
func (c *BaseConnection) SetStat(virtualPath string, attributes *StatAttributes) error {
if ok, policy := c.User.IsFileAllowed(virtualPath); !ok {
return c.GetErrorForDeniedFile(policy)
}
fs, fsPath, err := c.GetFsAndResolvedPath(virtualPath)
if err != nil {
return err
@@ -799,12 +826,12 @@ func (c *BaseConnection) isRenamePermitted(fsSrc, fsDst vfs.Fs, fsSourcePath, fs
c.Log(logger.LevelWarn, "renaming a virtual folder is not allowed")
return false
}
if !c.User.IsFileAllowed(virtualSourcePath) || !c.User.IsFileAllowed(virtualTargetPath) {
if fi != nil && fi.Mode().IsRegular() {
c.Log(logger.LevelDebug, "renaming file is not allowed, source: %#v target: %#v",
virtualSourcePath, virtualTargetPath)
return false
}
isSrcAllowed, _ := c.User.IsFileAllowed(virtualSourcePath)
isDstAllowed, _ := c.User.IsFileAllowed(virtualTargetPath)
if !isSrcAllowed || !isDstAllowed {
c.Log(logger.LevelDebug, "renaming source: %#v to target: %#v not allowed", virtualSourcePath,
virtualTargetPath)
return false
}
return c.hasRenamePerms(virtualSourcePath, virtualTargetPath, fi)
}
@@ -1141,6 +1168,16 @@ func (c *BaseConnection) IsNotExistError(err error) bool {
}
}
// GetErrorForDeniedFile return permission denied or not exist error based on the specified policy
func (c *BaseConnection) GetErrorForDeniedFile(policy int) error {
switch policy {
case sdk.DenyPolicyHide:
return c.GetNotExistError()
default:
return c.GetPermissionDeniedError()
}
}
// GetPermissionDeniedError returns an appropriate permission denied error for the connection protocol
func (c *BaseConnection) GetPermissionDeniedError() error {
switch c.protocol {