diff --git a/internal/common/common_test.go b/internal/common/common_test.go index cc85af0d..3024837c 100644 --- a/internal/common/common_test.go +++ b/internal/common/common_test.go @@ -1412,6 +1412,19 @@ func TestUserPerms(t *testing.T) { u.Permissions["/"] = []string{dataprovider.PermDeleteDirs, dataprovider.PermRenameFiles, dataprovider.PermRenameDirs} assert.False(t, u.HasPermsDeleteAll("/")) assert.True(t, u.HasPermsRenameAll("/")) + + toCheck := []string{dataprovider.PermDownload, dataprovider.PermUpload, dataprovider.PermCreateDirs, dataprovider.PermListItems, + dataprovider.PermOverwrite, dataprovider.PermDelete} + u.Permissions = make(map[string][]string) + u.Permissions["/"] = []string{dataprovider.PermListItems} + u.Permissions["/example-dir/bar"] = []string{dataprovider.PermListItems} + u.Permissions["/example-dir"] = toCheck + assert.True(t, u.HasPerms(toCheck, "/example-dir")) + assert.False(t, u.HasRecursivePerms(toCheck, "/example-dir")) + delete(u.Permissions, "/example-dir/bar") + assert.True(t, u.HasRecursivePerms(toCheck, "/example-dir")) + u.Permissions["/example-dirbar"] = []string{dataprovider.PermListItems} + assert.True(t, u.HasRecursivePerms(toCheck, "/example-dir")) } func TestGetTLSVersion(t *testing.T) { diff --git a/internal/dataprovider/user.go b/internal/dataprovider/user.go index c2d91bb7..0b4c2cf5 100644 --- a/internal/dataprovider/user.go +++ b/internal/dataprovider/user.go @@ -876,6 +876,27 @@ func (u *User) HasAnyPerm(permissions []string, path string) bool { return false } +// HasRecursivePerms returns true if the user has all the specified permissions +// in the given folder and in every subfolder that has explicit permissions +// defined. +func (u *User) HasRecursivePerms(permissions []string, virtualPath string) bool { + if !u.HasPerms(permissions, virtualPath) { + return false + } + for dir, perms := range u.Permissions { + if len(dir) > len(virtualPath) { + if strings.HasPrefix(dir, virtualPath+"/") { + for _, permission := range permissions { + if !slices.Contains(perms, permission) { + return false + } + } + } + } + } + return true +} + // HasPerms returns true if the user has all the given permissions func (u *User) HasPerms(permissions []string, path string) bool { perms := u.GetPermissionsForPath(path) diff --git a/internal/sftpd/ssh_cmd.go b/internal/sftpd/ssh_cmd.go index b0243d09..d4541ffb 100644 --- a/internal/sftpd/ssh_cmd.go +++ b/internal/sftpd/ssh_cmd.go @@ -262,7 +262,7 @@ func (c *sshCommand) executeSystemCommand(command systemCommand) error { //nolin } perms := []string{dataprovider.PermDownload, dataprovider.PermUpload, dataprovider.PermCreateDirs, dataprovider.PermListItems, dataprovider.PermOverwrite, dataprovider.PermDelete} - if !c.connection.User.HasPerms(perms, sshDestPath) { + if !c.connection.User.HasRecursivePerms(perms, sshDestPath) { return c.sendErrorResponse(c.connection.GetPermissionDeniedError()) }