Просмотр исходного кода

system commands: recursively verify required permissions

If any permission is missing at any level, return a "Permission Denied"
error

Signed-off-by: Nicola Murino <[email protected]>
Nicola Murino 1 месяц назад
Родитель
Сommit
e892748ef4
3 измененных файлов с 35 добавлено и 1 удалено
  1. 13 0
      internal/common/common_test.go
  2. 21 0
      internal/dataprovider/user.go
  3. 1 1
      internal/sftpd/ssh_cmd.go

+ 13 - 0
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) {

+ 21 - 0
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)

+ 1 - 1
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())
 	}