From 6506cf61bbf4a24777e297bf33317ed60934032f Mon Sep 17 00:00:00 2001 From: Umer Saleem Date: Mon, 3 Jul 2023 21:46:32 +0500 Subject: [PATCH] Add test suite for validating NFSv4.1 ACLs This commit adds test suite for NFSv4.1 ACLS. The test suite uses libzfsacl python bindings to validate functionality of NFS ACLs. The test suite validates the basic behavior of ACLs by verifying default ACEs and then moves to testing all the flags and permissions for deny and allow permissions. Test suite also verifies that allow ACEs don't work without setting the specific permission flag, i.e. to perform an operation, it's permission is required. Similarly, test suite also verifies that allow ACE for a specific permission only allows that perticular permission and user does not have access to other permissions. Signed-off-by: Umer Saleem --- .../openzfs-python3-libzfsacl.install.in | 1 + lib/libzfsacl/Makefile.am | 3 +- lib/libzfsacl/setup.py.in | 5 +- lib/libzfsacl/zfsacltests/__init__.py | 0 lib/libzfsacl/zfsacltests/test_nfsv4acl.py | 1531 +++++++++++++++++ rpm/generic/zfs.spec.in | 1 + tests/runfiles/common.run | 4 + tests/runfiles/sanity.run | 4 + tests/zfs-tests/tests/Makefile.am | 5 +- .../tests/functional/acl/nfsv4/.gitignore | 1 + .../tests/functional/acl/nfsv4/cleanup.ksh | 34 + .../functional/acl/nfsv4/nfsacl_001.ksh.in | 39 + .../tests/functional/acl/nfsv4/setup.ksh | 46 + 13 files changed, 1670 insertions(+), 4 deletions(-) create mode 100644 lib/libzfsacl/zfsacltests/__init__.py create mode 100644 lib/libzfsacl/zfsacltests/test_nfsv4acl.py create mode 100644 tests/zfs-tests/tests/functional/acl/nfsv4/.gitignore create mode 100755 tests/zfs-tests/tests/functional/acl/nfsv4/cleanup.ksh create mode 100755 tests/zfs-tests/tests/functional/acl/nfsv4/nfsacl_001.ksh.in create mode 100755 tests/zfs-tests/tests/functional/acl/nfsv4/setup.ksh diff --git a/contrib/debian/openzfs-python3-libzfsacl.install.in b/contrib/debian/openzfs-python3-libzfsacl.install.in index 80dc41607166..d1f845a8970b 100644 --- a/contrib/debian/openzfs-python3-libzfsacl.install.in +++ b/contrib/debian/openzfs-python3-libzfsacl.install.in @@ -1,4 +1,5 @@ usr/lib/python3/dist-packages/libzfsacl-*.egg-info usr/lib/python3/dist-packages/libzfsacl.cpython-*.so +usr/lib/python3/dist-packages/zfsacltests lib/@DEB_HOST_MULTIARCH@/libzfsacl.so.* lib/@DEB_HOST_MULTIARCH@/libsunacl.so.* diff --git a/lib/libzfsacl/Makefile.am b/lib/libzfsacl/Makefile.am index 2d63efc27a52..23b7b37b0bc2 100644 --- a/lib/libzfsacl/Makefile.am +++ b/lib/libzfsacl/Makefile.am @@ -1,5 +1,6 @@ dist_noinst_DATA += \ - %D%/libpyzfsacl.c + %D%/libpyzfsacl.c \ + %D%/zfsacltests SUBSTFILES += %D%/setup.py diff --git a/lib/libzfsacl/setup.py.in b/lib/libzfsacl/setup.py.in index 28693058486f..fbad9b4edf86 100644 --- a/lib/libzfsacl/setup.py.in +++ b/lib/libzfsacl/setup.py.in @@ -17,8 +17,9 @@ setup( version='@VERSION@', description='ACL wrapper library for acessing NFSv4 ACLs on Linux/FreeBSD', ext_modules=[libzfsacl_mod], - packages=find_packages(where=srcdir), - package_dir={"": os.path.relpath(srcdir)}, + packages=find_packages(where=srcdir) + ['zfsacltests'], + package_dir={"": os.path.relpath(srcdir), + "zfsacltests": os.path.relpath(srcdir) + '/zfsacltests'}, include_package_data=True, python_requires='>=3.6,<4', zip_safe=False, diff --git a/lib/libzfsacl/zfsacltests/__init__.py b/lib/libzfsacl/zfsacltests/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/lib/libzfsacl/zfsacltests/test_nfsv4acl.py b/lib/libzfsacl/zfsacltests/test_nfsv4acl.py new file mode 100644 index 000000000000..c258f98e146d --- /dev/null +++ b/lib/libzfsacl/zfsacltests/test_nfsv4acl.py @@ -0,0 +1,1531 @@ +import unittest +import os +import pwd +import shutil +import libzfsacl +import sys +from subprocess import run, PIPE + + +def run_as_user(cmd, user): + if shutil.which(cmd.split()[0]) is not None: + cmd = shutil.which(cmd.split()[0]) + " " + " ".join(cmd.split()[1:]) + command = ["/usr/bin/su", "-", user, "-c", cmd] + proc = run(command, stdout=PIPE, stderr=PIPE, + universal_newlines=True, timeout=30) + if proc.returncode != 0: + return {"result": False, "output": proc.stdout, + "error": proc.stderr, "returncode": proc.returncode} + else: + return {"result": True, "output": proc.stdout, + "error": proc.stderr, "returncode": proc.returncode} + + +class TestNFSAcl(unittest.TestCase): + + ZFS_ACL_STAFF_GROUP = "zfsgrp" + ZFS_ACL_STAFF1 = "staff1" + ZFS_ACL_STAFF2 = "staff2" + ZFS_ACL_STAFF1_UID = 0 + ZFS_ACL_STAFF2_UID = 0 + MOUNTPT = "/var/tmp/testdir" + TESTPOOL = "testpool" + TESTFS = "testfs" + TDIR = '/var/tmp/testdir/test' + USER_OBJ_PERMSET = libzfsacl.PERM_READ_DATA | \ + libzfsacl.PERM_LIST_DIRECTORY | libzfsacl.PERM_WRITE_DATA | \ + libzfsacl.PERM_ADD_FILE | libzfsacl.PERM_APPEND_DATA | \ + libzfsacl.PERM_ADD_SUBDIRECTORY | libzfsacl.PERM_READ_ATTRIBUTES | \ + libzfsacl.PERM_WRITE_ATTRIBUTES | libzfsacl.PERM_READ_NAMED_ATTRS | \ + libzfsacl.PERM_WRITE_NAMED_ATTRS | libzfsacl.PERM_READ_ACL | \ + libzfsacl.PERM_WRITE_ACL | libzfsacl.PERM_WRITE_OWNER | \ + libzfsacl.PERM_SYNCHRONIZE + OMIT_PERMSET = libzfsacl.PERM_READ_DATA | libzfsacl.PERM_WRITE_DATA | \ + libzfsacl.PERM_DELETE_CHILD | libzfsacl.PERM_READ_ATTRIBUTES | \ + libzfsacl.PERM_WRITE_ATTRIBUTES | libzfsacl.PERM_DELETE | \ + libzfsacl.PERM_READ_ACL | libzfsacl.PERM_WRITE_ACL | \ + libzfsacl.PERM_WRITE_OWNER | libzfsacl.PERM_EXECUTE + + # Init UIDs for ZFS users + def __init__(self, *args, **kwargs): + self.ZFS_ACL_STAFF1_UID = pwd.getpwnam(self.ZFS_ACL_STAFF1).pw_uid + self.ZFS_ACL_STAFF2_UID = pwd.getpwnam(self.ZFS_ACL_STAFF2).pw_uid + super(TestNFSAcl, self).__init__(*args, **kwargs) + + # Test pool ACL type is NFSv4 + def test_001_pool_acl_type(self): + acl = libzfsacl.Acl(path=f"/{self.TESTPOOL}") + self.assertEqual(libzfsacl.BRAND_NFSV4, acl.brand, + "ACL type is not NFSv4") + + # Test dataset mountpoint ACL type is NFSv4 + def test_002_fs_acl_type(self): + acl = libzfsacl.Acl(path=self.MOUNTPT) + self.assertEqual(libzfsacl.BRAND_NFSV4, acl.brand, + "ACL type is not NFSv4") + + # Test default ACE count + def test_003_default_ace_count(self): + acl = libzfsacl.Acl(path=self.MOUNTPT) + self.assertEqual(3, acl.ace_count, "Default ace count is not 3") + + # Try to get first ACE + def test_004_get_first_ace(self): + acl = libzfsacl.Acl(path=self.MOUNTPT) + entry0 = acl.get_entry(0) + self.assertEqual(0, entry0.idx, "Failed to get first ACE") + + # Try to get last ACE + def test_005_get_last_ace(self): + acl = libzfsacl.Acl(path=self.MOUNTPT) + entry0 = acl.get_entry(acl.ace_count - 1) + self.assertEqual(acl.ace_count - 1, entry0.idx, + "Failed to get last ACE") + + # Test default USER_OBJ ACE is present + def test_006_default_ace_user_obj(self): + acl = libzfsacl.Acl(path=self.MOUNTPT) + entry0 = acl.get_entry(0) + self.assertEqual(0, entry0.idx, "Default ACE 0 idx is not 0") + self.assertEqual(libzfsacl.ENTRY_TYPE_ALLOW, entry0.entry_type, + "Default ACE 0 is not ENTRY_TYPE_ALLOW") + self.assertEqual(0, entry0.flagset, + "Default ACE 0 flagset is not NO_INHERIT") + self.assertEqual(libzfsacl.WHOTYPE_USER_OBJ, entry0.who[0], + "ACE 0 who type is not USER_OBJ") + self.assertEqual(self.USER_OBJ_PERMSET, + entry0.permset & self.USER_OBJ_PERMSET, + "Default ACE 0 permset does not match" + "USER_OBJ_PERMSET") + + # Test default GROUP_OBJ ACE is present + def test_007_default_ace_group_obj(self): + acl = libzfsacl.Acl(path=self.MOUNTPT) + entry1 = acl.get_entry(1) + self.assertEqual(1, entry1.idx, "Default ACE 1 idx is not 1") + self.assertEqual(libzfsacl.ENTRY_TYPE_ALLOW, entry1.entry_type, + "Default ACE 1 is not ENTRY_TYPE_ALLOW") + self.assertEqual(libzfsacl.WHOTYPE_GROUP_OBJ, entry1.who[0], + "ACE 1 who type is not GROUP_OBJ") + + # Test default EVERYONE ACE is present + def test_008_default_ace_everyone(self): + acl = libzfsacl.Acl(path=self.MOUNTPT) + entry2 = acl.get_entry(2) + self.assertEqual(2, entry2.idx, "Default ACE 2 idx is not 1") + self.assertEqual(libzfsacl.ENTRY_TYPE_ALLOW, entry2.entry_type, + "Default ACE 2 is not ENTRY_TYPE_ALLOW") + self.assertEqual(0, entry2.flagset, + "Default ACE 2 flagset is not NO_INHERIT") + self.assertEqual(libzfsacl.WHOTYPE_EVERYONE, entry2.who[0], + "ACE 2 who type is not EVERYONE") + + # Test an ACE can be appended + def test_009_append_an_ace(self): + os.makedirs(self.TDIR) + dacl = libzfsacl.Acl(path=self.TDIR) + orig_cnt = dacl.ace_count + newEntry = dacl.create_entry() + newEntry.entry_type = libzfsacl.ENTRY_TYPE_ALLOW + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + dacl.setacl(path=self.TDIR) + new_cnt = libzfsacl.Acl(path=self.TDIR).ace_count + os.rmdir(self.TDIR) + self.assertEqual(orig_cnt + 1, new_cnt, "Failed to add an ace") + + # Test an ACE can be prepended + def test_010_prepend_an_ace(self): + os.makedirs(self.TDIR) + dacl = libzfsacl.Acl(path=self.TDIR) + orig_cnt = dacl.ace_count + newEntry = dacl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_ALLOW + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + dacl.setacl(path=self.TDIR) + new_cnt = libzfsacl.Acl(path=self.TDIR).ace_count + os.rmdir(self.TDIR) + self.assertEqual(orig_cnt + 1, new_cnt, "Failed to add an ace") + + # Test DENY ace can be set + def test_011_add_ace_set_entry_type_deny(self): + os.makedirs(self.TDIR) + tdacl = libzfsacl.Acl(path=self.TDIR) + newEntry = tdacl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_DENY + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + tdacl.setacl(path=self.TDIR) + tdacl_entry0 = libzfsacl.Acl(path=self.TDIR).get_entry(0) + os.rmdir(self.TDIR) + self.assertEqual(libzfsacl.ENTRY_TYPE_DENY, tdacl_entry0.entry_type, + "Failed to add deny ACE") + + # Test ALLOW ace can be set + def test_012_add_ace_set_entry_type_allow(self): + os.makedirs(self.TDIR) + tdacl = libzfsacl.Acl(path=self.TDIR) + newEntry = tdacl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_ALLOW + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + tdacl.setacl(path=self.TDIR) + tdacl_entry0 = libzfsacl.Acl(path=self.TDIR).get_entry(0) + os.rmdir(self.TDIR) + self.assertEqual(libzfsacl.ENTRY_TYPE_ALLOW, tdacl_entry0.entry_type, + "Failed to add allow ACE") + + # Test adding an ACE works on mountpoint + def test_013_add_ace_mountpoint(self): + mpacl = libzfsacl.Acl(path=self.MOUNTPT) + orig_cnt = mpacl.ace_count + newEntry = mpacl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_ALLOW + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + newEntry.flagset = 0 + newEntry.permset = libzfsacl.PERM_READ_DATA + mpacl.setacl(path=self.MOUNTPT) + self.assertEqual(orig_cnt + 1, mpacl.ace_count, + "Failed to add an ACE on mountpoint") + + # Test removing an ACE works on mountpoint + def test_014_remove_ace_mountpoint(self): + mpacl = libzfsacl.Acl(path=self.MOUNTPT) + orig_cnt = mpacl.ace_count + mpacl.delete_entry(0) + self.assertEqual(orig_cnt - 1, mpacl.ace_count, + "Failed to delete an ACE from mountpoint") + + # Test adding an ACE works on a directory + def test_015_add_ace_dir(self): + os.makedirs(self.TDIR) + dacl = libzfsacl.Acl(path=self.TDIR) + orig_cnt = dacl.ace_count + newEntry = dacl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_ALLOW + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + newEntry.flagset = 0 + newEntry.permset = libzfsacl.PERM_READ_DATA + dacl.setacl(path=self.TDIR) + self.assertEqual(orig_cnt + 1, dacl.ace_count, + "Failed to add an ACE on a directory") + + # Test removing an ace from a directory + def test_016_remove_ace_dir(self): + dacl = libzfsacl.Acl(path=self.TDIR) + orig_cnt = dacl.ace_count + dacl.delete_entry(0) + new_cnt = dacl.ace_count + os.rmdir(self.TDIR) + self.assertEqual(orig_cnt - 1, new_cnt, + "Failed to delete an ACE from a directory") + + # Test adding an ACE to a file + def test_017_add_ace_file(self): + tfile = f'{self.MOUNTPT}/test.txt' + with open(tfile, 'w'): + pass + facl = libzfsacl.Acl(path=tfile) + orig_cnt = facl.ace_count + newEntry = facl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_ALLOW + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + newEntry.flagset = 0 + newEntry.permset = libzfsacl.PERM_READ_DATA + facl.setacl(path=tfile) + self.assertEqual(orig_cnt + 1, facl.ace_count, + "Failed to add an ACE to a file") + + # Test removing an ace from a file + def test_018_remove_ace_file(self): + tfile = f'{self.MOUNTPT}/test.txt' + facl = libzfsacl.Acl(path=tfile) + orig_cnt = facl.ace_count + facl.delete_entry(0) + new_cnt = facl.ace_count + os.remove(tfile) + self.assertEqual(orig_cnt - 1, new_cnt, + "Failed to delete an ACE from a file") + + # Test a flag can be set on file + def test_019_basic_flagset(self): + tfile = f'{self.MOUNTPT}/test.txt' + with open(tfile, 'w'): + pass + facl = libzfsacl.Acl(path=tfile) + newEntry = facl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_ALLOW + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + newEntry.flagset = 0 + newEntry.permset = libzfsacl.PERM_READ_DATA + facl.setacl(path=tfile) + facl = libzfsacl.Acl(path=tfile) + facl_entry0 = facl.get_entry(0) + os.remove(tfile) + self.assertEqual(facl_entry0.flagset, 0, + "Failed to set basic flagset") + + # Test multiple flags can be set on directory + def test_020_advanced_flagset(self): + os.makedirs(self.TDIR) + tdacl = libzfsacl.Acl(path=self.TDIR) + adv_flags = libzfsacl.FLAG_FILE_INHERIT | \ + libzfsacl.FLAG_DIRECTORY_INHERIT | \ + libzfsacl.FLAG_NO_PROPAGATE_INHERIT | \ + libzfsacl.FLAG_INHERIT_ONLY + newEntry = tdacl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_ALLOW + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + newEntry.flagset = adv_flags + newEntry.permset = libzfsacl.PERM_READ_DATA + tdacl.setacl(path=self.TDIR) + tdacl = libzfsacl.Acl(path=self.TDIR) + tdacl_entry0 = tdacl.get_entry(0) + os.rmdir(self.TDIR) + self.assertEqual(tdacl_entry0.flagset, adv_flags, + "FLAG_INHERITED is set by default.") + + # Test no inherited ace is present by default + def test_021_flagset_no_inherited_ace_by_default(self): + os.makedirs(self.TDIR) + tdacl = libzfsacl.Acl(path=self.TDIR) + not_inherited = 0 + for i in range(tdacl.ace_count): + if tdacl.get_entry(i).flagset & libzfsacl.FLAG_INHERITED == 0: + not_inherited += 1 + os.rmdir(self.TDIR) + self.assertEqual(not_inherited, tdacl.ace_count, + "FLAG_INHERITED is set by default.") + + # Test FILE_INHERIT flag functions correctly + def test_022_flagset_file_inherit(self): + tfile = f'{self.TDIR}/test_file.txt' + os.makedirs(self.TDIR) + tdacl = libzfsacl.Acl(path=self.TDIR) + newEntry = tdacl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_ALLOW + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + newEntry.flagset = newEntry.flagset | libzfsacl.FLAG_FILE_INHERIT + newEntry.permset = libzfsacl.PERM_READ_DATA + tdacl.setacl(path=self.TDIR) + with open(tfile, 'w'): + pass + tfacl = libzfsacl.Acl(path=tfile) + tfacl_entry0 = tfacl.get_entry(0) + shutil.rmtree(self.TDIR) + self.assertEqual(libzfsacl.FLAG_INHERITED, tfacl_entry0.flagset, + "libzfsacl.FLAG_INHERITED is not set") + + # Test DIRECTORY_INHERIT functions correctly + def test_023_flagset_directory_inherit(self): + tddir = f'{self.TDIR}/test_dir' + os.makedirs(self.TDIR) + tdacl = libzfsacl.Acl(path=self.TDIR) + newEntry = tdacl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_ALLOW + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + newEntry.flagset = newEntry.flagset | libzfsacl.FLAG_DIRECTORY_INHERIT + newEntry.permset = libzfsacl.PERM_READ_DATA + tdacl.setacl(path=self.TDIR) + os.makedirs(tddir) + tfacl = libzfsacl.Acl(path=tddir) + tfacl_entry0 = tfacl.get_entry(0) + shutil.rmtree(self.TDIR) + self.assertEqual(libzfsacl.FLAG_INHERITED | + libzfsacl.FLAG_DIRECTORY_INHERIT, + tfacl_entry0.flagset, + "libzfsacl.FLAG_DIRECTORY_INHERIT is not set") + + # Test NO_PROPAGATE_INHERIT functions correctly + def test_024_flagset_no_propagate_inherit(self): + tddir = f'{self.TDIR}/test_dir' + ttdir = f'{tddir}/test' + os.makedirs(self.TDIR) + tdacl = libzfsacl.Acl(path=self.TDIR) + newEntry = tdacl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_ALLOW + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + newEntry.flagset = newEntry.flagset | \ + libzfsacl.FLAG_DIRECTORY_INHERIT | \ + libzfsacl.FLAG_NO_PROPAGATE_INHERIT + newEntry.permset = libzfsacl.PERM_READ_DATA + tdacl.setacl(path=self.TDIR) + os.makedirs(tddir) + os.makedirs(ttdir) + ttdacl = libzfsacl.Acl(path=ttdir) + not_inherited = 0 + for i in range(ttdacl.ace_count): + if ttdacl.get_entry(i).flagset & libzfsacl.FLAG_INHERITED == 0: + not_inherited += 1 + shutil.rmtree(self.TDIR) + self.assertEqual(ttdacl.ace_count, not_inherited, + "libzfsacl.FLAG_NO_PROPAGATE_INHERIT is not " + "functioning properly") + + # Test INHERIT_ONLY flag behavior on dirs, if DIRECTORY_INHERIT was + # set with INHERIT_ONLY, it is removed from child dirs. If not, + # INHERIT_ONLY should be set on shild dirs. + def test_025_flagset_inherit_only_dir(self): + tddir = f'{self.TDIR}/test_dir' + os.makedirs(self.TDIR) + tdacl = libzfsacl.Acl(path=self.TDIR) + newEntry = tdacl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_ALLOW + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + newEntry.flagset = libzfsacl.FLAG_DIRECTORY_INHERIT | \ + libzfsacl.FLAG_FILE_INHERIT | \ + libzfsacl.FLAG_INHERIT_ONLY + newEntry.permset = libzfsacl.PERM_READ_DATA | \ + libzfsacl.PERM_WRITE_DATA + tdacl.setacl(path=self.TDIR) + os.makedirs(tddir) + tddacl = libzfsacl.Acl(path=tddir) + tdentry0 = tddacl.get_entry(0) + tflags = libzfsacl.FLAG_DIRECTORY_INHERIT | \ + libzfsacl.FLAG_FILE_INHERIT | libzfsacl.FLAG_INHERITED + self.assertEqual(tdentry0.idx, 0, + "Idx of inherited ACE at index 0 should be 0") + self.assertEqual(tdentry0.entry_type, libzfsacl.ENTRY_TYPE_ALLOW, + "Inherited ACE at index 0 should be of type allow") + self.assertEqual(tdentry0.who, + (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID), + "Inherited ACE who is not correct") + self.assertEqual(tdentry0.flagset, tflags, + "Flagset on inherited ACE are not correct") + self.assertEqual(tdentry0.permset, + libzfsacl.PERM_READ_DATA | libzfsacl.PERM_WRITE_DATA, + "Permse of inherited ACE at index 0 are not correct") + os.rmdir(tddir) + tdacl.delete_entry(0) + tdacl.setacl(path=self.TDIR) + newEntry = tdacl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_ALLOW + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + newEntry.flagset = libzfsacl.FLAG_FILE_INHERIT | \ + libzfsacl.FLAG_INHERIT_ONLY + newEntry.permset = libzfsacl.PERM_READ_DATA | \ + libzfsacl.PERM_WRITE_DATA + tdacl.setacl(path=self.TDIR) + os.makedirs(tddir) + tddacl = libzfsacl.Acl(path=tddir) + tdentry0 = tddacl.get_entry(0) + shutil.rmtree(self.TDIR) + tflags = libzfsacl.FLAG_FILE_INHERIT | libzfsacl.FLAG_INHERITED | \ + libzfsacl.FLAG_INHERIT_ONLY + self.assertEqual(tdentry0.idx, 0, + "Idx of inherited ACE at index 0 should be 0") + self.assertEqual(tdentry0.entry_type, libzfsacl.ENTRY_TYPE_ALLOW, + "Inherited ACE at index 0 should be of type allow") + self.assertEqual(tdentry0.who, + (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID), + "Inherited ACE who is not correct") + self.assertEqual(tdentry0.flagset, tflags, + "Flagset on inherited ACE are not correct") + self.assertEqual(tdentry0.permset, + libzfsacl.PERM_READ_DATA | libzfsacl.PERM_WRITE_DATA, + "Permse of inherited ACE at index 0 are not correct") + + # Test INHERIT_ONLY flag behavior on files, ACE should be inheritted + def test_026_flagset_inherit_only_file(self): + tfile = f'{self.TDIR}/test.txt' + os.makedirs(self.TDIR) + tdacl = libzfsacl.Acl(path=self.TDIR) + newEntry = tdacl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_ALLOW + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + newEntry.flagset = libzfsacl.FLAG_DIRECTORY_INHERIT | \ + libzfsacl.FLAG_FILE_INHERIT | libzfsacl.FLAG_INHERIT_ONLY + newEntry.permset = libzfsacl.PERM_READ_DATA | libzfsacl.PERM_WRITE_DATA + tdacl.setacl(path=self.TDIR) + with open(tfile, 'w'): + pass + tfacl = libzfsacl.Acl(path=tfile) + tfentry0 = tfacl.get_entry(0) + shutil.rmtree(self.TDIR) + self.assertEqual(tfentry0.idx, 0, + "Idx of inherited ACE at index 0 should be 0") + self.assertEqual(tfentry0.entry_type, libzfsacl.ENTRY_TYPE_ALLOW, + "Inherited ACE at index 0 should be of type allow") + self.assertEqual(tfentry0.who, + (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID), + "Inherited ACE who is not correct") + self.assertEqual(tfentry0.flagset, libzfsacl.FLAG_INHERITED, + "Flagset on inherited ACE are not correct") + self.assertEqual(tfentry0.permset, + libzfsacl.PERM_READ_DATA | libzfsacl.PERM_WRITE_DATA, + "Permse of inherited ACE at index 0 are not correct") + + # Test INHERIT_ONLY flag with NO_PROPAGATE_INHERIT, ACE should be + # inherited but inheritance flags should be removed + def test_027_flagset_no_propagate_dir(self): + tddir = f'{self.TDIR}/test_dir' + os.makedirs(self.TDIR) + tdacl = libzfsacl.Acl(path=self.TDIR) + newEntry = tdacl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_ALLOW + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + newEntry.flagset = libzfsacl.FLAG_DIRECTORY_INHERIT | \ + libzfsacl.FLAG_INHERIT_ONLY | libzfsacl.FLAG_NO_PROPAGATE_INHERIT + newEntry.permset = libzfsacl.PERM_READ_DATA | \ + libzfsacl.PERM_WRITE_DATA + tdacl.setacl(path=self.TDIR) + os.makedirs(tddir) + tddacl = libzfsacl.Acl(path=tddir) + tdentry0 = tddacl.get_entry(0) + shutil.rmtree(self.TDIR) + self.assertEqual(tdentry0.idx, 0, + "Idx of inherited ACE at index 0 should be 0") + self.assertEqual(tdentry0.entry_type, libzfsacl.ENTRY_TYPE_ALLOW, + "Inherited ACE at index 0 should be of type allow") + self.assertEqual(tdentry0.who, + (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID), + "Inherited ACE who is not correct") + self.assertEqual(tdentry0.flagset, libzfsacl.FLAG_INHERITED, + "Flagset on inherited ACE are not correct") + self.assertEqual(tdentry0.permset, + libzfsacl.PERM_READ_DATA | libzfsacl.PERM_WRITE_DATA, + "Permse of inherited ACE at index 0 are not correct") + + # Following test cases verify that deny ACE permsets work correclty. + # Prepend deny ACE denying that particular permission to the the ZFS + # ACL user, then attempt to perform an action that should result in + # failure. + + # Confirm deny ACE works for PERM_READ_DATA. + def test_028_permset_deny_read_data(self): + tfile = f'{self.TDIR}/test.txt' + os.makedirs(self.TDIR) + with open(tfile, 'w') as file: + file.write("This is a test file.") + tfacl = libzfsacl.Acl(path=tfile) + newEntry = tfacl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_DENY + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + newEntry.flagset = 0 + newEntry.permset = libzfsacl.PERM_READ_DATA + tfacl.setacl(path=tfile) + cmd = f"cat {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + shutil.rmtree(self.TDIR) + self.assertEqual(res["result"], False, "Failed to deny PERM_READ_DATA") + + # Test deny ACE works for PERM_WRITE_DATA + def test_029_permset_deny_write_data(self): + tfile = f'{self.TDIR}/test.txt' + os.makedirs(self.TDIR) + tdacl = libzfsacl.Acl(path=self.TDIR) + newEntry = tdacl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_DENY + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + newEntry.flagset = 0 + newEntry.permset = libzfsacl.PERM_WRITE_DATA + tdacl.setacl(path=self.TDIR) + cmd = f"touch {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + shutil.rmtree(self.TDIR) + self.assertEqual(res["result"], False, + "Failed to deny PERM_WRITE_DATA") + + # Test deny ACE works for PERM_EXECUTE + def test_030_permset_deny_execute(self): + os.makedirs(self.TDIR) + tdacl = libzfsacl.Acl(path=self.TDIR) + newEntry = tdacl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_DENY + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + newEntry.flagset = 0 + newEntry.permset = libzfsacl.PERM_EXECUTE + tdacl.setacl(path=self.TDIR) + cmd = f"cd {self.TDIR}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + os.rmdir(self.TDIR) + self.assertEqual(res["result"], False, "Failed to deny PERM_EXECUTE") + + # Test deny ACE works for PERM_READ_ATTRIBUTES + # PERM_READ_ATTRIBUTES is not implemented on Linux. It has no + # equivalent in POSIX ACLs + @unittest.skipIf(sys.platform == 'linux', + "PERM_READ_ATTRIBUTES is not supported for Linux") + def test_031_permset_deny_read_attrs(self): + tfile = f'{self.TDIR}/test.txt' + os.makedirs(self.TDIR) + with open(tfile, 'w'): + pass + tfacl = libzfsacl.Acl(path=tfile) + newEntry = tfacl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_DENY + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + newEntry.flagset = 0 + newEntry.permset = libzfsacl.PERM_READ_ATTRIBUTES + tfacl.setacl(path=tfile) + cmd = f"stat {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + shutil.rmtree(self.TDIR) + self.assertEqual(res["result"], False, + "Failed to deny PERM_READ_ATTRIBUTES") + + # Test deny ACE works for PERM_WRITE_ATTRIBUTES + def test_032_permset_deny_write_attrs(self): + tfile = f'{self.TDIR}/test.txt' + os.makedirs(self.TDIR) + with open(tfile, 'w'): + pass + tfacl = libzfsacl.Acl(path=tfile) + newEntry = tfacl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_DENY + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + newEntry.flagset = 0 + newEntry.permset = libzfsacl.PERM_WRITE_ATTRIBUTES + tfacl.setacl(path=tfile) + cmd = f"touch a -m -t 201512180130.09 {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + shutil.rmtree(self.TDIR) + self.assertEqual(res["result"], False, + "Failed to deny PERM_WRITE_ATTRIBUTES") + + # Test deny ACE works for PERM_DELETE + def test_033_permset_deny_delete(self): + tfile = f'{self.TDIR}/test.txt' + os.makedirs(self.TDIR) + with open(tfile, 'w'): + pass + tfacl = libzfsacl.Acl(path=tfile) + newEntry = tfacl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_DENY + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + newEntry.flagset = 0 + newEntry.permset = libzfsacl.PERM_DELETE + tfacl.setacl(path=tfile) + cmd = f"rm -f {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + shutil.rmtree(self.TDIR) + self.assertEqual(res["result"], False, "Failed to deny PERM_DELETE") + + # Test deny ACE works for PERM_DELETE_CHILD + def test_034_permset_deny_delete_child(self): + tddir = f'{self.TDIR}/test_dir' + os.makedirs(self.TDIR) + os.makedirs(tddir) + tddacl = libzfsacl.Acl(path=tddir) + newEntry = tddacl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_DENY + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + newEntry.flagset = 0 + newEntry.permset = libzfsacl.PERM_DELETE_CHILD + tddacl.setacl(path=tddir) + cmd = f"rm -rf {tddir}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + shutil.rmtree(self.TDIR) + self.assertEqual(res["result"], False, + "Failed to deny PERM_DELETE_CHILD") + + # Test deny ACE works for PERM_READ_ACL + def test_035_permset_deny_read_acl(self): + tfile = f'{self.TDIR}/test.txt' + os.makedirs(self.TDIR) + with open(tfile, 'w'): + pass + tfacl = libzfsacl.Acl(path=tfile) + newEntry = tfacl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_DENY + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + newEntry.flagset = 0 + newEntry.permset = libzfsacl.PERM_READ_ACL + tfacl.setacl(path=tfile) + cmd = f"zfs_getnfs4facl {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + shutil.rmtree(self.TDIR) + self.assertEqual(res["result"], False, "Failed to deny PERM_READ_ACL") + + # Test deny ACE works for PERM_WRITE_ACL + def test_036_permset_deny_write_acl(self): + tfile = f'{self.TDIR}/test.txt' + os.makedirs(self.TDIR) + with open(tfile, 'w'): + pass + tfacl = libzfsacl.Acl(path=tfile) + newEntry = tfacl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_DENY + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + newEntry.flagset = 0 + newEntry.permset = libzfsacl.PERM_WRITE_ACL + tfacl.setacl(path=tfile) + cmd = f"zfs_setnfs4facl -x 0 {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + shutil.rmtree(self.TDIR) + self.assertEqual(res["result"], False, "Failed to deny PERM_WRITE_ACL") + + # Test deny ACE works for PERM_WRITE_OWNER + def test_037_permset_deny_write_owner(self): + tfile = f'{self.TDIR}/test.txt' + os.makedirs(self.TDIR) + with open(tfile, 'w'): + pass + tfacl = libzfsacl.Acl(path=tfile) + newEntry = tfacl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_DENY + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + newEntry.flagset = 0 + newEntry.permset = libzfsacl.PERM_WRITE_OWNER + tfacl.setacl(path=tfile) + cmd = f"chown {self.ZFS_ACL_STAFF1} {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + shutil.rmtree(self.TDIR) + self.assertEqual(res["result"], False, + "Failed to deny PERM_WRITE_OWNER") + + # Test deny ACE works for PERM_ADD_FILE + def test_038_permset_deny_add_file(self): + tddir = f'{self.TDIR}/test_dir' + tfile = f'{self.TDIR}/test_dir/test.txt' + os.makedirs(self.TDIR) + os.makedirs(tddir) + tfacl = libzfsacl.Acl(path=tddir) + newEntry = tfacl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_DENY + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + newEntry.flagset = 0 + newEntry.permset = libzfsacl.PERM_ADD_FILE + tfacl.setacl(path=tddir) + cmd = f"touch {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + shutil.rmtree(self.TDIR) + self.assertEqual(res["result"], False, "Failed to deny PERM_ADD_FILE") + + # Following test cases verify that allow ACE permsets work + # correclty. Prepend allow ACE that allows a particular permission + # to the ZFS ACL user, then attempt to perform an action that should + # result in success. + + # Test allow ACE works for PERM_READ_DATA + def test_039_permset_allow_read_data(self): + tfile = f'{self.TDIR}/test.txt' + os.makedirs(self.TDIR) + with open(tfile, 'w') as file: + file.write("This is a test file.") + tfacl = libzfsacl.Acl(path=tfile) + newEntry = tfacl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_ALLOW + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + newEntry.flagset = 0 + newEntry.permset = libzfsacl.PERM_READ_DATA | libzfsacl.PERM_EXECUTE + tfacl.setacl(path=tfile) + cmd = f"cat {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + shutil.rmtree(self.TDIR) + self.assertEqual(res["result"], True, "Failed to allow PERM_READ_DATA") + + # Test allow ACE works for PERM_WRITE_DATA + def test_040_permset_allow_write_data(self): + tfile = f'{self.TDIR}/test.txt' + os.makedirs(self.TDIR) + with open(tfile, 'w') as file: + file.write("This is a test file.") + tfacl = libzfsacl.Acl(path=tfile) + newEntry = tfacl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_ALLOW + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + newEntry.flagset = 0 + newEntry.permset = libzfsacl.PERM_WRITE_DATA + tfacl.setacl(path=tfile) + cmd = f'echo -n "CAT" >> {tfile}' + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + shutil.rmtree(self.TDIR) + self.assertEqual(res["result"], True, + "Failed to allow PERM_WRITE_DATA") + + # Test allow ACE works for PERM_EXECUTE + def test_041_permset_allow_execute(self): + os.makedirs(self.TDIR) + tdacl = libzfsacl.Acl(path=self.TDIR) + newEntry = tdacl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_ALLOW + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + newEntry.flagset = 0 + newEntry.permset = libzfsacl.PERM_EXECUTE + tdacl.setacl(path=self.TDIR) + cmd = f"cd {self.TDIR}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + os.rmdir(self.TDIR) + self.assertEqual(res["result"], True, "Failed to allow PERM_EXECUTE") + + # Test allow ACE works for PERM_READ_ATTRIBUTES + def test_042_permset_allow_read_attrs(self): + tfile = f'{self.TDIR}/test.txt' + os.makedirs(self.TDIR) + with open(tfile, 'w'): + pass + tfacl = libzfsacl.Acl(path=tfile) + newEntry = tfacl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_ALLOW + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + newEntry.flagset = 0 + newEntry.permset = libzfsacl.PERM_READ_ATTRIBUTES | \ + libzfsacl.PERM_EXECUTE + tfacl.setacl(path=tfile) + cmd = f"stat {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + shutil.rmtree(self.TDIR) + self.assertEqual(res["result"], True, + "Failed to allow PERM_READ_ATTRIBUTES") + + # Test allow ACE works for PERM_WRITE_ATTRIBUTES + def test_043_permset_allow_write_attrs(self): + tfile = f'{self.TDIR}/test.txt' + os.makedirs(self.TDIR) + tfacl = libzfsacl.Acl(path=self.TDIR) + newEntry = tfacl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_ALLOW + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + newEntry.flagset = 0 + newEntry.permset = libzfsacl.PERM_WRITE_DATA | \ + libzfsacl.PERM_WRITE_ATTRIBUTES + tfacl.setacl(path=self.TDIR) + cmd = f"touch -a -m -t 201512180130.09 {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + shutil.rmtree(self.TDIR) + self.assertEqual(res["result"], True, + "Failed to allow PERM_WRITE_ATTRIBUTES") + + # Test allow ACE works for PERM_DELETE + def test_044_permset_allow_delete(self): + tfile = f'{self.TDIR}/test.txt' + os.makedirs(self.TDIR) + with open(tfile, 'w'): + pass + tdacl = libzfsacl.Acl(path=self.TDIR) + newEntry = tdacl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_ALLOW + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + newEntry.flagset = 0 + newEntry.permset = libzfsacl.PERM_DELETE | libzfsacl.PERM_EXECUTE | \ + libzfsacl.PERM_WRITE_DATA + tdacl.setacl(path=self.TDIR) + cmd = f"rm -f {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + shutil.rmtree(self.TDIR) + self.assertEqual(res["result"], True, "Failed to allow PERM_DELETE") + + # Test allow ACE works for PERM_DELETE_CHILD + def test_045_permset_allow_delete_child(self): + tddir = f'{self.TDIR}/test_dir' + os.makedirs(self.TDIR) + os.makedirs(tddir) + os.makedirs(f"{tddir}/tmp") + tfacl = libzfsacl.Acl(path=tddir) + newEntry = tfacl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_ALLOW + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + newEntry.flagset = 0 + newEntry.permset = libzfsacl.PERM_DELETE_CHILD | \ + libzfsacl.PERM_EXECUTE | libzfsacl.PERM_WRITE_DATA + tfacl.setacl(path=tddir) + cmd = f"rm -rf {tddir}/tmp" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + shutil.rmtree(self.TDIR) + self.assertEqual(res["result"], True, + "Failed to allow PERM_DELETE_CHILD") + + # Test allow ACE works for PERM_READ_ACL + def test_046_permset_allow_read_acl(self): + tfile = f'{self.TDIR}/test.txt' + os.makedirs(self.TDIR) + with open(tfile, 'w'): + pass + tfacl = libzfsacl.Acl(path=tfile) + newEntry = tfacl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_ALLOW + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + newEntry.flagset = 0 + newEntry.permset = libzfsacl.PERM_READ_ACL + tfacl.setacl(path=tfile) + cmd = f"zfs_getnfs4facl {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + shutil.rmtree(self.TDIR) + self.assertEqual(res["result"], True, "Failed to allow PERM_READ_ACL") + + # Test allow ACE works for PERM_WRITE_ACL + def test_047_permset_allow_write_acl(self): + tfile = f'{self.TDIR}/test.txt' + os.makedirs(self.TDIR) + with open(tfile, 'w'): + pass + tfacl = libzfsacl.Acl(path=tfile) + newEntry = tfacl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_ALLOW + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + newEntry.flagset = 0 + newEntry.permset = libzfsacl.PERM_WRITE_ACL + tfacl.setacl(path=tfile) + cmd = f"zfs_setnfs4facl -a u:{self.ZFS_ACL_STAFF1}:rw-pD-aARWcCos:" + \ + f"-------:allow {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + shutil.rmtree(self.TDIR) + self.assertEqual(res["result"], True, + "Failed to allow PERM_WRITE_ACL") + + # Test allow ACE works for PERM_WRITE_OWNER + # PERM_WRITE_OWNER requires updates in Linux kernel, specifically in + # setattr_prepare(), for permission check for chown and chgrp. + # Without updates in Linux kernel to add permissions check, + # PERM_WRITE_OWNER is not suported on Linux. + @unittest.skipIf(sys.platform == 'linux', + "PERM_WRITE_OWNER is not supported for Linux") + def test_048_permset_allow_write_owner(self): + tfile = f'{self.TDIR}/test.txt' + os.makedirs(self.TDIR) + with open(tfile, 'w'): + pass + tfacl = libzfsacl.Acl(path=tfile) + newEntry = tfacl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_ALLOW + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + newEntry.flagset = 0 + newEntry.permset = libzfsacl.PERM_WRITE_OWNER | \ + libzfsacl.PERM_EXECUTE | libzfsacl.PERM_WRITE_DATA | \ + libzfsacl.PERM_READ_ATTRIBUTES | libzfsacl.PERM_WRITE_ATTRIBUTES + tfacl.setacl(path=tfile) + cmd = f"chown {self.ZFS_ACL_STAFF1} {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + shutil.rmtree(self.TDIR) + self.assertEqual(res["result"], True, + "Failed to allow PERM_WRITE_OWNER") + + # Test allow ACE works for PERM_ADD_FILE + def test_049_permset_allow_add_file(self): + tfile = f'{self.TDIR}/test.txt' + os.makedirs(self.TDIR) + tdacl = libzfsacl.Acl(path=self.TDIR) + newEntry = tdacl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_ALLOW + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + newEntry.flagset = 0 + newEntry.permset = libzfsacl.PERM_ADD_FILE + tdacl.setacl(path=self.TDIR) + cmd = f"touch {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + shutil.rmtree(self.TDIR) + self.assertEqual(res["result"], True, "Failed to allow PERM_ADD_FILE") + + # Following test cases verify that allow ACE permsets don't work + # without the specific flag set that is required to perform that + # operation. Prepend allow ACE that allows all permissions, but the + # one that is required to perform a particular operation. This + # should result in failure. + + # Omit PERM_READ_DATA and test reading data + def test_050_permset_omit_read_data(self): + tfile = f'{self.TDIR}/test.txt' + os.makedirs(self.TDIR) + with open(tfile, 'w') as file: + file.write("This is a test file.") + tfacl = libzfsacl.Acl(path=tfile) + tfacl.delete_entry(2) + newEntry = tfacl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_ALLOW + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + newEntry.flagset = 0 + newEntry.permset = self.OMIT_PERMSET & ~(libzfsacl.PERM_READ_DATA) + tfacl.setacl(path=tfile) + cmd = f"cat {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + shutil.rmtree(self.TDIR) + self.assertEqual(res["result"], False) + + # Omit PERM_WRITE_DATA and test writing data + def test_051_permset_omit_write_data(self): + tfile = f'{self.TDIR}/test.txt' + os.makedirs(self.TDIR) + with open(tfile, 'w') as file: + file.write("This is a test file.") + tfacl = libzfsacl.Acl(path=tfile) + newEntry = tfacl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_ALLOW + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + newEntry.flagset = 0 + newEntry.permset = self.OMIT_PERMSET & ~(libzfsacl.PERM_WRITE_DATA) + tfacl.setacl(path=tfile) + cmd = f'echo -n "CAT" >> {tfile}' + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + shutil.rmtree(self.TDIR) + self.assertEqual(res["result"], False) + + # Test omit for PERM_EXECUTE + def test_052_permset_omit_execute(self): + os.makedirs(self.TDIR) + tdacl = libzfsacl.Acl(path=self.TDIR) + tdacl.delete_entry(2) + newEntry = tdacl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_ALLOW + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + newEntry.flagset = 0 + newEntry.permset = self.OMIT_PERMSET & ~(libzfsacl.PERM_EXECUTE) + tdacl.setacl(path=self.TDIR) + cmd = f"cd {self.TDIR}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + os.rmdir(self.TDIR) + self.assertEqual(res["result"], False) + + # Test omit for PERM_READ_ATTRIBUTES + # PERM_READ_ATTRIBUTES is not implemented on Linux. It has no + # equivalent in POSIX ACLs + @unittest.skipIf(sys.platform == 'linux', + "PERM_READ_ATTRIBUTES is not implemented for Linux") + def test_053_permset_omit_read_attrs(self): + tfile = f'{self.TDIR}/test.txt' + os.makedirs(self.TDIR) + with open(tfile, 'w'): + pass + tfacl = libzfsacl.Acl(path=tfile) + tfacl.delete_entry(2) + newEntry = tfacl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_ALLOW + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + newEntry.flagset = 0 + newEntry.permset = self.OMIT_PERMSET & \ + ~(libzfsacl.PERM_READ_ATTRIBUTES) + tfacl.setacl(path=tfile) + cmd = f"stat {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + shutil.rmtree(self.TDIR) + self.assertEqual(res["result"], False) + + # Test omit for PERM_WRITE_ATTRIBUTES + def test_054_permset_omit_write_attrs(self): + tfile = f'{self.TDIR}/test.txt' + os.makedirs(self.TDIR) + with open(tfile, 'w'): + pass + tfacl = libzfsacl.Acl(path=tfile) + newEntry = tfacl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_ALLOW + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + newEntry.flagset = 0 + newEntry.permset = self.OMIT_PERMSET & \ + ~(libzfsacl.PERM_WRITE_ATTRIBUTES | libzfsacl.PERM_EXECUTE | + libzfsacl.PERM_WRITE_DATA) + tfacl.setacl(path=tfile) + cmd = f"touch a -m -t 201512180130.09 {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + shutil.rmtree(self.TDIR) + self.assertEqual(res["result"], False) + + # Test omit for PERM_DELETE + def test_055_permset_omit_delete(self): + tfile = f'{self.TDIR}/test.txt' + os.makedirs(self.TDIR) + with open(tfile, 'w'): + pass + tdacl = libzfsacl.Acl(path=self.TDIR) + newEntry = tdacl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_ALLOW + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + newEntry.flagset = 0 + newEntry.permset = self.OMIT_PERMSET & \ + ~(libzfsacl.PERM_DELETE | libzfsacl.PERM_DELETE_CHILD | + libzfsacl.PERM_EXECUTE | libzfsacl.PERM_WRITE_DATA) + tdacl.setacl(path=self.TDIR) + cmd = f"rm -f {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + shutil.rmtree(self.TDIR) + self.assertEqual(res["result"], False) + + # Test omit for PERM_DELETE_CHILD + def test_056_permset_omit_delete_child(self): + tddir = f'{self.TDIR}/test_dir' + os.makedirs(self.TDIR) + os.makedirs(tddir) + os.makedirs(f"{tddir}/tmp") + tfacl = libzfsacl.Acl(path=tddir) + newEntry = tfacl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_ALLOW + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + newEntry.flagset = 0 + newEntry.permset = self.OMIT_PERMSET & \ + ~(libzfsacl.PERM_DELETE_CHILD | libzfsacl.PERM_EXECUTE | + libzfsacl.PERM_WRITE_DATA) + tfacl.setacl(path=tddir) + cmd = f"rm -rf {tddir}/tmp" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + shutil.rmtree(self.TDIR) + self.assertEqual(res["result"], False) + + # Test omit for PERM_READ_ACL + def test_057_permset_omit_read_acl(self): + tfile = f'{self.TDIR}/test.txt' + os.makedirs(self.TDIR) + with open(tfile, 'w'): + pass + tfacl = libzfsacl.Acl(path=tfile) + tfacl.delete_entry(2) + newEntry = tfacl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_ALLOW + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + newEntry.flagset = 0 + newEntry.permset = self.OMIT_PERMSET & ~(libzfsacl.PERM_READ_ACL) + tfacl.setacl(path=tfile) + cmd = f"zfs_getnfs4facl {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + shutil.rmtree(self.TDIR) + self.assertEqual(res["result"], False) + + # Test omit for PERM_WRITE_ACL + def test_058_permset_omit_write_acl(self): + tfile = f'{self.TDIR}/test.txt' + os.makedirs(self.TDIR) + with open(tfile, 'w'): + pass + tfacl = libzfsacl.Acl(path=tfile) + newEntry = tfacl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_ALLOW + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + newEntry.flagset = 0 + newEntry.permset = self.OMIT_PERMSET & ~(libzfsacl.PERM_WRITE_ACL) + tfacl.setacl(path=tfile) + cmd = f"zfs_setnfs4facl -x 0 {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + shutil.rmtree(self.TDIR) + self.assertEqual(res["result"], False) + + # Test omit for PERM_WRITE_OWNER + def test_059_permset_omit_write_owner(self): + tfile = f'{self.TDIR}/test.txt' + os.makedirs(self.TDIR) + with open(tfile, 'w'): + pass + tfacl = libzfsacl.Acl(path=tfile) + newEntry = tfacl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_ALLOW + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + newEntry.flagset = 0 + newEntry.permset = self.OMIT_PERMSET & ~(libzfsacl.PERM_WRITE_OWNER) + tfacl.setacl(path=tfile) + cmd = f"chown {self.ZFS_ACL_STAFF1} {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + shutil.rmtree(self.TDIR) + self.assertEqual(res["result"], False) + + # Test omit for PERM_ADD_FILE + def test_060_permset_omit_add_file(self): + tfile = f'{self.TDIR}/test.txt' + os.makedirs(self.TDIR) + tdacl = libzfsacl.Acl(path=self.TDIR) + newEntry = tdacl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_ALLOW + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + newEntry.flagset = 0 + newEntry.permset = self.OMIT_PERMSET & ~(libzfsacl.PERM_ADD_FILE) + tdacl.setacl(path=self.TDIR) + cmd = f"touch {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + shutil.rmtree(self.TDIR) + self.assertEqual(res["result"], False) + + # Following test cases verify that allow ACE permsets only allows a + # user to perform that operation, and user does not have access to + # other permissions. Add and ACE that allows the ZFS ACL user to + # perform an operation, then perform other operations that are not + # permitted to that user. This should result in failure. + + # User is allowed to stat on Linux since, PERM_READ_ATTRIBUTES is not + # implemented on Linux. + + # Test allowing PERM_READ_DATA only allows reading data + def test_061_permset_restrict_read_data(self): + tfile = f'{self.TDIR}/test.txt' + os.makedirs(self.TDIR) + with open(tfile, 'w') as file: + file.write("This is a test file.") + tfacl = libzfsacl.Acl(path=tfile) + tfacl.delete_entry(2) + newEntry = tfacl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_ALLOW + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + newEntry.flagset = 0 + newEntry.permset = libzfsacl.PERM_READ_DATA + tfacl.setacl(path=tfile) + cmd = f'echo -n "CAT" >> {tfile}' + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_READ_DATA") + cmd = f"touch a -m -t 201512180130.09 {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_READ_DATA") + cmd = f"rm -f {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_READ_DATA") + cmd = f"chown {self.ZFS_ACL_STAFF1} {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_READ_DATA") + cmd = f"zfs_getnfs4facl {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_READ_DATA") + cmd = f"zfs_setnfs4facl -x 0 {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_READ_DATA") + if sys.platform != 'linux': + cmd = f"stat {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_READ_DATA") + shutil.rmtree(self.TDIR) + + # Test allowing PERM_WRITE_DATA only allows writing data + def test_062_permset_restrict_write_data(self): + tfile = f'{self.TDIR}/test.txt' + os.makedirs(self.TDIR) + with open(tfile, 'w') as file: + file.write("This is a test file.") + tfacl = libzfsacl.Acl(path=tfile) + tfacl.delete_entry(2) + newEntry = tfacl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_ALLOW + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + newEntry.flagset = 0 + newEntry.permset = libzfsacl.PERM_WRITE_DATA + tfacl.setacl(path=tfile) + cmd = f"cat {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_WRITE_DATA") + cmd = f"touch a -m -t 201512180130.09 {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_WRITE_DATA") + cmd = f"rm -f {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_WRITE_DATA") + cmd = f"chown {self.ZFS_ACL_STAFF1} {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_WRITE_DATA") + cmd = f"zfs_getnfs4facl {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_WRITE_DATA") + cmd = f"zfs_setnfs4facl -x 0 {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_WRITE_DATA") + if sys.platform != 'linux': + cmd = f"stat {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_WRITE_DATA") + shutil.rmtree(self.TDIR) + + # Test allowing PERM_EXECUTE only allows execution + def test_063_permset_restrict_execute(self): + os.makedirs(self.TDIR) + tfile = f'{self.TDIR}/test.txt' + with open(tfile, 'w'): + pass + tdacl = libzfsacl.Acl(path=self.TDIR) + tdacl.delete_entry(2) + newEntry = tdacl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_ALLOW + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + newEntry.flagset = 0 + newEntry.permset = libzfsacl.PERM_EXECUTE + tdacl.setacl(path=self.TDIR) + cmd = f"ls {self.TDIR}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_EXECUTE") + cmd = f'echo -n "CAT" >> {tfile}' + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_EXECUTE") + cmd = f"touch a -m -t 201512180130.09 {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_EXECUTE") + cmd = f"rm -f {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_EXECUTE") + cmd = f"chown {self.ZFS_ACL_STAFF1} {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_EXECUTE") + cmd = f"zfs_getnfs4facl {self.TDIR}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_EXECUTE") + cmd = f"zfs_setnfs4facl -x 0 {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_EXECUTE") + shutil.rmtree(self.TDIR) + + # Test allowing PERM_READ_ATTRIBUTES only allows to read attributes + def test_064_permset_restrict_read_attrs(self): + tfile = f'{self.TDIR}/test.txt' + os.makedirs(self.TDIR) + with open(tfile, 'w'): + pass + tfacl = libzfsacl.Acl(path=tfile) + tfacl.delete_entry(2) + newEntry = tfacl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_ALLOW + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + newEntry.flagset = 0 + newEntry.permset = libzfsacl.PERM_READ_ATTRIBUTES + tfacl.setacl(path=tfile) + cmd = f"cat {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_READ_ATTRIBUTES") + cmd = f'echo -n "CAT" >> {tfile}' + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_READ_ATTRIBUTES") + cmd = f"touch a -m -t 201512180130.09 {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_READ_ATTRIBUTES") + cmd = f"rm -f {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_READ_ATTRIBUTES") + cmd = f"chown {self.ZFS_ACL_STAFF1} {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_READ_ATTRIBUTES") + cmd = f"zfs_getnfs4facl {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_READ_ATTRIBUTES") + cmd = f"zfs_setnfs4facl -x 0 {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_READ_ATTRIBUTES") + shutil.rmtree(self.TDIR) + + # Test allowing PERM_WRITE_ATTRIBUTES only allows to write attributes + def test_065_permset_restrict_write_attrs(self): + tfile = f'{self.TDIR}/test.txt' + os.makedirs(self.TDIR) + with open(tfile, 'w'): + pass + tfacl = libzfsacl.Acl(path=tfile) + tfacl.delete_entry(2) + newEntry = tfacl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_ALLOW + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + newEntry.flagset = 0 + newEntry.permset = libzfsacl.PERM_WRITE_ATTRIBUTES + tfacl.setacl(path=tfile) + cmd = f"cat {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_WRITE_ATTRIBUTES") + cmd = f'echo -n "CAT" >> {tfile}' + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_WRITE_ATTRIBUTES") + cmd = f"rm -f {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_WRITE_ATTRIBUTES") + cmd = f"chown {self.ZFS_ACL_STAFF1} {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_WRITE_ATTRIBUTES") + cmd = f"zfs_getnfs4facl {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_WRITE_ATTRIBUTES") + cmd = f"zfs_setnfs4facl -x 0 {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_WRITE_ATTRIBUTES") + if sys.platform != 'linux': + cmd = f"stat {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_WRITE_ATTRIBUTES") + shutil.rmtree(self.TDIR) + + # Test allowing PERM_DELETE only allows to delete + def test_066_permset_restrict_delete(self): + tfile = f'{self.TDIR}/test.txt' + os.makedirs(self.TDIR) + with open(tfile, 'w'): + pass + tdacl = libzfsacl.Acl(path=self.TDIR) + tdacl.delete_entry(2) + newEntry = tdacl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_ALLOW + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + newEntry.flagset = 0 + newEntry.permset = libzfsacl.PERM_DELETE + tdacl.setacl(path=self.TDIR) + cmd = f"ls {self.TDIR}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_DELETE") + cmd = f'echo -n "CAT" >> {tfile}' + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_DELETE") + cmd = f"touch a -m -t 201512180130.09 {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_DELETE") + cmd = f"chown {self.ZFS_ACL_STAFF1} {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_DELETE") + cmd = f"zfs_getnfs4facl {self.TDIR}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_DELETE") + cmd = f"zfs_setnfs4facl -x 0 {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_DELETE") + if sys.platform != 'linux': + cmd = f"stat {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_DELETE") + shutil.rmtree(self.TDIR) + + # Test allowing PERM_READ_ACL only allows to read ACL + def test_067_permset_restrict_read_acl(self): + tfile = f'{self.TDIR}/test.txt' + os.makedirs(self.TDIR) + with open(tfile, 'w'): + pass + tdacl = libzfsacl.Acl(path=self.TDIR) + tdacl.delete_entry(2) + newEntry = tdacl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_ALLOW + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + newEntry.flagset = 0 + newEntry.permset = libzfsacl.PERM_READ_ACL + tdacl.setacl(path=self.TDIR) + cmd = f"ls {self.TDIR}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_READ_ACL") + cmd = f'echo -n "CAT" >> {tfile}' + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_READ_ACL") + cmd = f"touch a -m -t 201512180130.09 {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_READ_ACL") + cmd = f"rm -f {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_READ_ACL") + cmd = f"chown {self.ZFS_ACL_STAFF1} {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_READ_ACL") + cmd = f"zfs_setnfs4facl -x 0 {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_READ_ACL") + if sys.platform != 'linux': + cmd = f"stat {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_READ_ACL") + shutil.rmtree(self.TDIR) + + # Test allowing PERM_WRITE_ACL only allows to write ACL + def test_068_permset_restrict_write_acl(self): + tfile = f'{self.TDIR}/test.txt' + os.makedirs(self.TDIR) + with open(tfile, 'w'): + pass + tdacl = libzfsacl.Acl(path=self.TDIR) + tdacl.delete_entry(2) + newEntry = tdacl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_ALLOW + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + newEntry.flagset = 0 + newEntry.permset = libzfsacl.PERM_WRITE_ACL + tdacl.setacl(path=self.TDIR) + cmd = f"ls {self.TDIR}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_WRITE_ACL") + cmd = f'echo -n "CAT" >> {tfile}' + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_WRITE_ACL") + cmd = f"touch a -m -t 201512180130.09 {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_WRITE_ACL") + cmd = f"rm -f {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_WRITE_ACL") + cmd = f"chown {self.ZFS_ACL_STAFF1} {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_WRITE_ACL") + cmd = f"zfs_getnfs4facl {self.TDIR}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_WRITE_ACL") + if sys.platform != 'linux': + cmd = f"stat {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_WRITE_ACL") + shutil.rmtree(self.TDIR) + + # Test allowing PERM_WRITE_OWNER only allows to write owner + def test_069_permset_restrict_write_owner(self): + tfile = f'{self.TDIR}/test.txt' + os.makedirs(self.TDIR) + with open(tfile, 'w'): + pass + tfacl = libzfsacl.Acl(path=tfile) + tfacl.delete_entry(2) + newEntry = tfacl.create_entry(0) + newEntry.entry_type = libzfsacl.ENTRY_TYPE_ALLOW + newEntry.who = (libzfsacl.WHOTYPE_USER, self.ZFS_ACL_STAFF1_UID) + newEntry.flagset = 0 + newEntry.permset = libzfsacl.PERM_WRITE_OWNER + tfacl.setacl(path=tfile) + cmd = f"cat {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_WRITE_OWNER") + cmd = f'echo -n "CAT" >> {tfile}' + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_WRITE_OWNER") + cmd = f"touch a -m -t 201512180130.09 {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_WRITE_OWNER") + cmd = f"rm -f {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_WRITE_OWNER") + cmd = f"zfs_getnfs4facl {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_WRITE_OWNER") + cmd = f"zfs_setnfs4facl -x 0 {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_WRITE_OWNER") + if sys.platform != 'linux': + cmd = f"stat {tfile}" + res = run_as_user(cmd, self.ZFS_ACL_STAFF1) + self.assertEqual(res["result"], False, + "Failed to restrict PERM_WRITE_OWNER") + shutil.rmtree(self.TDIR) diff --git a/rpm/generic/zfs.spec.in b/rpm/generic/zfs.spec.in index 637a41813775..55efad010b5e 100644 --- a/rpm/generic/zfs.spec.in +++ b/rpm/generic/zfs.spec.in @@ -612,5 +612,6 @@ systemctl --system daemon-reload >/dev/null || true %files -n python%{__python_pkg_version}-libzfsacl %{__python_sitelib}/libzfsacl-*/* %{__python_sitelib}/libzfsacl.cpython*.so +%{__python_sitelib}/zfsacltests/* %{_libdir}/libzfsacl.so.* %{_libdir}/libsunacl.so.* diff --git a/tests/runfiles/common.run b/tests/runfiles/common.run index 47f8de0dd4c1..b7428da7ba23 100644 --- a/tests/runfiles/common.run +++ b/tests/runfiles/common.run @@ -28,6 +28,10 @@ failsafe = callbacks/zfs_failsafe outputdir = /var/tmp/test_results tags = ['functional'] +[tests/functional/acl/nfsv4] +tests = ['nfsacl_001'] +tags = ['functional', 'acl', 'nfsv4'] + [tests/functional/acl/off] tests = ['dosmode', 'posixmode'] tags = ['functional', 'acl'] diff --git a/tests/runfiles/sanity.run b/tests/runfiles/sanity.run index ab41c05b8473..796c43cd3d2b 100644 --- a/tests/runfiles/sanity.run +++ b/tests/runfiles/sanity.run @@ -30,6 +30,10 @@ failsafe = callbacks/zfs_failsafe outputdir = /var/tmp/test_results tags = ['functional'] +[tests/functional/acl/nfsv4] +tests = ['nfsacl_001'] +tags = ['functional', 'acl', 'nfsv4'] + [tests/functional/acl/off] tests = ['posixmode'] tags = ['functional', 'acl'] diff --git a/tests/zfs-tests/tests/Makefile.am b/tests/zfs-tests/tests/Makefile.am index 2fc54301bbeb..78436f7f97ee 100644 --- a/tests/zfs-tests/tests/Makefile.am +++ b/tests/zfs-tests/tests/Makefile.am @@ -72,7 +72,8 @@ regen: nobase_nodist_datadir_zfs_tests_tests_DATA = \ functional/pam/utilities.kshlib nobase_nodist_datadir_zfs_tests_tests_SCRIPTS = \ - functional/pyzfs/pyzfs_unittest.ksh + functional/pyzfs/pyzfs_unittest.ksh \ + functional/acl/nfsv4/nfsacl_001.ksh SUBSTFILES += $(nobase_nodist_datadir_zfs_tests_tests_DATA) $(nobase_nodist_datadir_zfs_tests_tests_SCRIPTS) @@ -390,6 +391,8 @@ nobase_dist_datadir_zfs_tests_tests_DATA += \ functional/idmap_mount/idmap_mount_common.kshlib nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \ + functional/acl/nfsv4/cleanup.ksh \ + functional/acl/nfsv4/setup.ksh \ functional/acl/off/cleanup.ksh \ functional/acl/off/dosmode.ksh \ functional/acl/off/posixmode.ksh \ diff --git a/tests/zfs-tests/tests/functional/acl/nfsv4/.gitignore b/tests/zfs-tests/tests/functional/acl/nfsv4/.gitignore new file mode 100644 index 000000000000..ed356dd820b0 --- /dev/null +++ b/tests/zfs-tests/tests/functional/acl/nfsv4/.gitignore @@ -0,0 +1 @@ +nfsacl_001.ksh diff --git a/tests/zfs-tests/tests/functional/acl/nfsv4/cleanup.ksh b/tests/zfs-tests/tests/functional/acl/nfsv4/cleanup.ksh new file mode 100755 index 000000000000..a378434d4afa --- /dev/null +++ b/tests/zfs-tests/tests/functional/acl/nfsv4/cleanup.ksh @@ -0,0 +1,34 @@ +#!/bin/ksh -p +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or https://opensource.org/licenses/CDDL-1.0. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2023 iXsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +. $STF_SUITE/include/libtest.shlib +. $STF_SUITE/tests/functional/acl/acl_common.kshlib + +cleanup_user_group + +default_cleanup + diff --git a/tests/zfs-tests/tests/functional/acl/nfsv4/nfsacl_001.ksh.in b/tests/zfs-tests/tests/functional/acl/nfsv4/nfsacl_001.ksh.in new file mode 100755 index 000000000000..5d33bc3b6e7a --- /dev/null +++ b/tests/zfs-tests/tests/functional/acl/nfsv4/nfsacl_001.ksh.in @@ -0,0 +1,39 @@ +#!/bin/ksh -p +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or https://opensource.org/licenses/CDDL-1.0. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2023 iXsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +. $STF_SUITE/include/libtest.shlib +. $STF_SUITE/tests/functional/acl/acl_common.kshlib + +verify_runnable "global" +log_assert "Verify NFSv4.1 ACLs behave correctly" + +@PYTHON@ -m unittest --verbose zfsacltests.test_nfsv4acl +if [ $? -ne 0 ]; then + log_fail "NFSv4.1 ACL tests completed with errors" +fi + +log_pass "NFSv4.1 ACL tests completed without errors" diff --git a/tests/zfs-tests/tests/functional/acl/nfsv4/setup.ksh b/tests/zfs-tests/tests/functional/acl/nfsv4/setup.ksh new file mode 100755 index 000000000000..50dc1154b191 --- /dev/null +++ b/tests/zfs-tests/tests/functional/acl/nfsv4/setup.ksh @@ -0,0 +1,46 @@ +#!/bin/ksh -p +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or https://opensource.org/licenses/CDDL-1.0. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2023 iXsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +. $STF_SUITE/include/libtest.shlib +. $STF_SUITE/tests/functional/acl/acl_common.kshlib + +cleanup_user_group + +# Create staff group and add user to it +log_must add_group $ZFS_ACL_STAFF_GROUP +log_must add_user $ZFS_ACL_STAFF_GROUP $ZFS_ACL_STAFF1 +log_must add_user $ZFS_ACL_STAFF_GROUP $ZFS_ACL_STAFF2 + +DISK=${DISKS%% *} +default_setup_noexit $DISK +log_must chmod 777 $TESTDIR + +# Use NFSv4 ACLs on filesystem +log_must zfs set acltype=nfsv4 $TESTPOOL +log_must zfs set acltype=nfsv4 $TESTPOOL/$TESTFS + +log_pass