diff options
author | Martin Matuska <martin@matuska.org> | 2017-03-02 14:19:38 +0100 |
---|---|---|
committer | Martin Matuska <martin@matuska.org> | 2017-03-02 16:10:26 +0100 |
commit | f5d473ed0b708f59f34c702891792efc9bb0817f (patch) | |
tree | c209007a2c49fd08ee93f7cc8bd40cb7501ed6a5 | |
parent | 60f0931d3b97e00616d7122321e34116d926bcc5 (diff) | |
download | libarchive-f5d473ed0b708f59f34c702891792efc9bb0817f.tar.gz |
New tar test: test_option_acls
Add sunacl_get() and setTestAcl() to common test code
Test for membership.h on Mac OS X and make it a requirement for ACLs
-rw-r--r-- | CMakeLists.txt | 1 | ||||
-rw-r--r-- | Makefile.am | 1 | ||||
-rw-r--r-- | build/cmake/config.h.in | 3 | ||||
-rw-r--r-- | cat/test/CMakeLists.txt | 5 | ||||
-rw-r--r-- | configure.ac | 1 | ||||
-rw-r--r-- | cpio/test/CMakeLists.txt | 5 | ||||
-rw-r--r-- | libarchive/archive_platform.h | 2 | ||||
-rw-r--r-- | libarchive/test/test_acl_platform_nfs4.c | 143 | ||||
-rw-r--r-- | libarchive/test/test_acl_platform_posix1e.c | 130 | ||||
-rw-r--r-- | tar/test/CMakeLists.txt | 6 | ||||
-rw-r--r-- | tar/test/test_option_acls.c | 471 | ||||
-rw-r--r-- | test_utils/test_common.h | 17 | ||||
-rw-r--r-- | test_utils/test_main.c | 235 |
13 files changed, 753 insertions, 267 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 5bcff485..bddf30c7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -579,6 +579,7 @@ int main(void) { return FS_IOC_GETFLAGS; }" HAVE_WORKING_FS_IOC_GETFLAGS) LA_CHECK_INCLUDE_FILE("linux/magic.h" HAVE_LINUX_MAGIC_H) LA_CHECK_INCLUDE_FILE("locale.h" HAVE_LOCALE_H) +LA_CHECK_INCLUDE_FILE("membership.h" HAVE_MEMBERSHIP_H) LA_CHECK_INCLUDE_FILE("memory.h" HAVE_MEMORY_H) LA_CHECK_INCLUDE_FILE("paths.h" HAVE_PATHS_H) LA_CHECK_INCLUDE_FILE("poll.h" HAVE_POLL_H) diff --git a/Makefile.am b/Makefile.am index 600e1ff4..b5a41f98 100644 --- a/Makefile.am +++ b/Makefile.am @@ -951,6 +951,7 @@ bsdtar_test_SOURCES= \ tar/test/test_option_T_upper.c \ tar/test/test_option_U_upper.c \ tar/test/test_option_X_upper.c \ + tar/test/test_option_acls.c \ tar/test/test_option_a.c \ tar/test/test_option_b.c \ tar/test/test_option_b64encode.c \ diff --git a/build/cmake/config.h.in b/build/cmake/config.h.in index fd4fbdcd..8c18edf8 100644 --- a/build/cmake/config.h.in +++ b/build/cmake/config.h.in @@ -773,6 +773,9 @@ typedef uint64_t uintmax_t; /* Define to 1 if you have the `mbrtowc' function. */ #cmakedefine HAVE_MBRTOWC 1 +/* Define to 1 if you have the <membership.h> header file. */ +#cmakedefine HAVE_MEMBERSHIP_H 1 + /* Define to 1 if you have the `memmove' function. */ #cmakedefine HAVE_MEMMOVE 1 diff --git a/cat/test/CMakeLists.txt b/cat/test/CMakeLists.txt index 7f1ce5e7..0623cc36 100644 --- a/cat/test/CMakeLists.txt +++ b/cat/test/CMakeLists.txt @@ -29,6 +29,11 @@ IF(ENABLE_CAT AND ENABLE_TEST) # Register target # ADD_EXECUTABLE(bsdcat_test ${bsdcat_test_SOURCES}) + IF(ENABLE_ACL) + IF(HAVE_LIBACL) + TARGET_LINK_LIBRARIES(bsdcat_test ${ACL_LIBRARY}) + ENDIF(HAVE_LIBACL) + ENDIF(ENABLE_ACL) SET_PROPERTY(TARGET bsdcat_test PROPERTY COMPILE_DEFINITIONS LIST_H) # diff --git a/configure.ac b/configure.ac index b9f7f53d..0592279d 100644 --- a/configure.ac +++ b/configure.ac @@ -699,6 +699,7 @@ AC_ARG_ENABLE([acl], if test "x$enable_acl" != "xno"; then AC_CHECK_HEADERS([acl/libacl.h]) AC_CHECK_HEADERS([sys/acl.h]) + AC_CHECK_HEADERS([membership.h]) AC_CHECK_LIB([acl],[acl_get_file]) AC_CHECK_FUNCS([acl_create_entry acl_get_fd_np]) AC_CHECK_FUNCS([acl_init acl_set_fd acl_set_fd_np acl_set_file]) diff --git a/cpio/test/CMakeLists.txt b/cpio/test/CMakeLists.txt index ec9509be..cc5fe011 100644 --- a/cpio/test/CMakeLists.txt +++ b/cpio/test/CMakeLists.txt @@ -62,6 +62,11 @@ IF(ENABLE_CPIO AND ENABLE_TEST) # Register target # ADD_EXECUTABLE(bsdcpio_test ${bsdcpio_test_SOURCES}) + IF(ENABLE_ACL) + IF(HAVE_LIBACL) + TARGET_LINK_LIBRARIES(bsdcpio_test ${ACL_LIBRARY}) + ENDIF(HAVE_LIBACL) + ENDIF(ENABLE_ACL) SET_PROPERTY(TARGET bsdcpio_test PROPERTY COMPILE_DEFINITIONS LIST_H) # diff --git a/libarchive/archive_platform.h b/libarchive/archive_platform.h index 128f0e08..01d6a70d 100644 --- a/libarchive/archive_platform.h +++ b/libarchive/archive_platform.h @@ -150,7 +150,7 @@ #if HAVE_SYS_ACL_H && HAVE_ACL_CREATE_ENTRY && HAVE_ACL_INIT && HAVE_ACL_SET_FILE #if HAVE_DECL_ACL_USER #define HAVE_POSIX_ACL 1 -#elif HAVE_DECL_ACL_TYPE_EXTENDED +#elif HAVE_DECL_ACL_TYPE_EXTENDED && HAVE_MEMBERSHIP_H #define HAVE_DARWIN_ACL 1 #endif #if HAVE_DECL_ACL_TYPE_NFS4 diff --git a/libarchive/test/test_acl_platform_nfs4.c b/libarchive/test/test_acl_platform_nfs4.c index 5783e523..c8854082 100644 --- a/libarchive/test/test_acl_platform_nfs4.c +++ b/libarchive/test/test_acl_platform_nfs4.c @@ -248,63 +248,6 @@ static struct myacl_t acls_dir[] = { static const int acls_dir_cnt = (int)(sizeof(acls_dir)/sizeof(acls_dir[0])); -#if HAVE_SUN_ACL -static void * -sunacl_get(int cmd, int *aclcnt, int fd, const char *path) -{ - int cnt, cntcmd; - size_t size; - void *aclp; - - if (cmd == GETACL) { - cntcmd = GETACLCNT; - size = sizeof(aclent_t); - } -#if HAVE_SUN_NFS4_ACL - else if (cmd == ACE_GETACL) { - cntcmd = ACE_GETACLCNT; - size = sizeof(ace_t); - } -#endif - else { - errno = EINVAL; - *aclcnt = -1; - return (NULL); - } - - aclp = NULL; - cnt = -2; - while (cnt == -2 || (cnt == -1 && errno == ENOSPC)) { - if (path != NULL) - cnt = acl(path, cntcmd, 0, NULL); - else - cnt = facl(fd, cntcmd, 0, NULL); - - if (cnt > 0) { - if (aclp == NULL) - aclp = malloc(cnt * size); - else - aclp = realloc(NULL, cnt * size); - if (aclp != NULL) { - if (path != NULL) - cnt = acl(path, cmd, cnt, aclp); - else - cnt = facl(fd, cmd, cnt, aclp); - } - } else { - if (aclp != NULL) { - free(aclp); - aclp = NULL; - } - break; - } - } - - *aclcnt = cnt; - return (aclp); -} -#endif /* HAVE_SUN_ACL */ - static void set_acls(struct archive_entry *ae, struct myacl_t *acls, int start, int end) { @@ -777,11 +720,10 @@ DEFINE_TEST(test_acl_platform_nfs4) skipping("NFS4 ACLs are not supported on this platform"); #else char buff[64]; + int i; struct stat st; struct archive *a; struct archive_entry *ae; - int i; - char *func; #if HAVE_DARWIN_ACL /* On MacOS we skip trivial ACLs in some tests */ const int regcnt = acls_reg_cnt - 4; const int dircnt = acls_dir_cnt - 4; @@ -793,92 +735,15 @@ DEFINE_TEST(test_acl_platform_nfs4) void *aclp; int aclcnt; #else /* !HAVE_SUN_NFS4_ACL */ -#if HAVE_DARWIN_ACL - acl_entry_t aclent; - acl_permset_t permset; - const uid_t uid = 1000; - uuid_t uuid; -#endif /* HAVE_DARWIN_ACL */ - int n; acl_t acl; -#endif /* !HAVE_SUN_NFS4_ACL */ - - /* - * First, do a quick manual set/read of ACL data to - * verify that the local filesystem does support ACLs. - * If it doesn't, we'll simply skip the remaining tests. - */ -#if HAVE_FREEBSD_NFS4_ACL - acl = acl_from_text("owner@:rwxp::allow,group@:rwp:f:allow"); - failure("acl_from_text(): errno = %d (%s)", errno, strerror(errno)); - assert((void *)acl != NULL); -#elif HAVE_DARWIN_ACL - acl = acl_init(1); - assert((void *)acl != NULL); - assertEqualInt(0, acl_create_entry(&acl, &aclent)); - assertEqualInt(0, acl_set_tag_type(aclent, ACL_EXTENDED_ALLOW)); - assertEqualInt(0, acl_get_permset(aclent, &permset)); - assertEqualInt(0, acl_add_perm(permset, ACL_READ_DATA)); - assertEqualInt(0, acl_add_perm(permset, ACL_WRITE_DATA)); - assertEqualInt(0, acl_add_perm(permset, ACL_APPEND_DATA)); - assertEqualInt(0, acl_add_perm(permset, ACL_EXECUTE)); - assertEqualInt(0, acl_set_permset(aclent, permset)); - assertEqualInt(0, mbr_identifier_to_uuid(ID_TYPE_UID, &uid, - sizeof(uid_t), uuid)); - assertEqualInt(0, acl_set_qualifier(aclent, uuid)); #endif - /* Create a test dir and try to set an ACL on it. */ - if (!assertMakeDir("pretest", 0755)) { -#if !HAVE_SUN_NFS4_ACL - acl_free(acl); -#endif - return; - } + assertMakeFile("pretest", 0644, "a"); -#if HAVE_SUN_NFS4_ACL - func = "acl()"; - aclp = sunacl_get(GETACL, &aclcnt, 0, "pretest"); - if (aclp != NULL) { - skipping("NFS4 ACL is not supported on this filesystem"); - free(aclp); + if (setTestAcl("pretest") != ARCHIVE_TEST_ACL_TYPE_NFS4) { + skipping("NFS4 ACLs are not writable on this filesystem"); return; } - free(aclp); - aclp = sunacl_get(ACE_GETACL, &aclcnt, 0, "pretest"); -#else - func = "acl_set_file()"; -#if HAVE_DARWIN_ACL - n = acl_set_file("pretest", ACL_TYPE_EXTENDED, acl); -#else - n = acl_set_file("pretest", ACL_TYPE_NFS4, acl); -#endif - acl_free(acl); -#endif -#if HAVE_SUN_NFS4_ACL - if (aclp == NULL) -#else - if (n != 0) -#endif - { -#if HAVE_SUN_NFS4_ACL - if (errno == ENOSYS || errno == ENOTSUP) -#else - if (errno == EOPNOTSUPP || errno == EINVAL) -#endif - { - skipping("NFS4 ACL is not supported on this filesystem"); - return; - } - } - failure("%s: errno = %d (%s)", func, errno, strerror(errno)); -#if HAVE_SUN_NFS4_ACL - assert(aclp != NULL); - free(aclp); - aclp = NULL; -#else - assertEqualInt(0, n); -#endif /* Create a write-to-disk object. */ assert(NULL != (a = archive_write_disk_new())); diff --git a/libarchive/test/test_acl_platform_posix1e.c b/libarchive/test/test_acl_platform_posix1e.c index a0da2273..0224a57f 100644 --- a/libarchive/test/test_acl_platform_posix1e.c +++ b/libarchive/test/test_acl_platform_posix1e.c @@ -35,63 +35,6 @@ __FBSDID("$FreeBSD: head/lib/libarchive/test/test_acl_freebsd.c 189427 2009-03-0 #define ACL_GET_PERM acl_get_perm_np #endif -#if HAVE_SUN_ACL -static void * -sunacl_get(int cmd, int *aclcnt, int fd, const char *path) -{ - int cnt, cntcmd; - size_t size; - void *aclp; - - if (cmd == GETACL) { - cntcmd = GETACLCNT; - size = sizeof(aclent_t); - } -#if HAVE_SUN_NFS4_ACL - else if (cmd == ACE_GETACL) { - cntcmd = ACE_GETACLCNT; - size = sizeof(ace_t); - } -#endif - else { - errno = EINVAL; - *aclcnt = -1; - return (NULL); - } - - aclp = NULL; - cnt = -2; - while (cnt == -2 || (cnt == -1 && errno == ENOSPC)) { - if (path != NULL) - cnt = acl(path, cntcmd, 0, NULL); - else - cnt = facl(fd, cntcmd, 0, NULL); - - if (cnt > 0) { - if (aclp == NULL) - aclp = malloc(cnt * size); - else - aclp = realloc(NULL, cnt * size); - if (aclp != NULL) { - if (path != NULL) - cnt = acl(path, cmd, cnt, aclp); - else - cnt = facl(fd, cmd, cnt, aclp); - } - } else { - if (aclp != NULL) { - free(aclp); - aclp = NULL; - } - break; - } - } - - *aclcnt = cnt; - return (aclp); -} -#endif /* HAVE_SUN_ACL */ - static struct archive_test_acl_t acls2[] = { { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_EXECUTE | ARCHIVE_ENTRY_ACL_READ, ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" }, @@ -361,8 +304,6 @@ DEFINE_TEST(test_acl_platform_posix1e_restore) struct stat st; struct archive *a; struct archive_entry *ae; - int n, fd; - char *func; #if HAVE_SUN_ACL void *aclp; int aclcnt; @@ -370,77 +311,12 @@ DEFINE_TEST(test_acl_platform_posix1e_restore) acl_t acl; #endif - /* - * First, do a quick manual set/read of ACL data to - * verify that the local filesystem does support ACLs. - * If it doesn't, we'll simply skip the remaining tests. - */ -#if HAVE_SUN_ACL - aclent_t aclp1[] = { - { USER_OBJ, -1, 4 | 2 | 1 }, - { USER, 1, 4 | 2 }, - { GROUP_OBJ, -1, 4 | 2 | 1 }, - { GROUP, 15, 4 | 1 }, - { CLASS_OBJ, -1, 4 | 2 | 1 }, - { OTHER_OBJ, -1, 4 | 2 | 1 } - }; -#else - acl = acl_from_text("u::rwx,u:1:rw,g::rwx,g:15:rx,o::rwx,m::rwx"); - failure("acl_from_text(): errno = %d (%s)", errno, strerror(errno)); - assert((void *)acl != NULL); -#endif - - /* Create a test file and try ACL on it. */ - fd = open("pretest", O_WRONLY | O_CREAT | O_EXCL, 0777); - failure("Could not create test file?!"); - if (!assert(fd >= 0)) { -#if !HAVE_SUN_ACL - acl_free(acl); -#endif - return; - } + assertMakeFile("pretest", 0644, "a"); -#if HAVE_SUN_ACL - aclp = sunacl_get(GETACL, &aclcnt, fd, NULL); - if (aclp == NULL) - close(fd); - if (errno == ENOSYS || errno == ENOTSUP) { - skipping("POSIX.1e ACLs are not supported on this filesystem"); - return; - } - failure("facl(): errno = %d (%s)", errno, strerror(errno)); - if (assert(aclp != NULL) == 0) { - free(aclp); + if (setTestAcl("pretest") != ARCHIVE_TEST_ACL_TYPE_POSIX1E) { + skipping("POSIX.1e ACLs are not writable on this filesystem"); return; } - free(aclp); - aclp = NULL; - - func = "facl()"; - n = facl(fd, SETACL, (int)(sizeof(aclp1)/sizeof(aclp1[0])), &aclp1); -#else - func = "acl_set_fd()"; - n = acl_set_fd(fd, acl); -#endif -#if !HAVE_SUN_ACL - acl_free(acl); -#endif - if (n != 0) { -#if HAVE_SUN_ACL - if (errno == ENOSYS || errno == ENOTSUP) -#else - if (errno == EOPNOTSUPP || errno == EINVAL) -#endif - { - close(fd); - skipping("POSIX.1e ACLs are not supported on this filesystem"); - return; - } - } - failure("%s: errno = %d (%s)", func, errno, strerror(errno)); - assertEqualInt(0, n); - - close(fd); /* Create a write-to-disk object. */ assert(NULL != (a = archive_write_disk_new())); diff --git a/tar/test/CMakeLists.txt b/tar/test/CMakeLists.txt index 9115d6f6..e6054bab 100644 --- a/tar/test/CMakeLists.txt +++ b/tar/test/CMakeLists.txt @@ -34,6 +34,7 @@ IF(ENABLE_TAR AND ENABLE_TEST) test_option_U_upper.c test_option_X_upper.c test_option_a.c + test_option_acls.c test_option_b.c test_option_b64encode.c test_option_exclude.c @@ -72,6 +73,11 @@ IF(ENABLE_TAR AND ENABLE_TEST) # Register target # ADD_EXECUTABLE(bsdtar_test ${bsdtar_test_SOURCES}) + IF(ENABLE_ACL) + IF(HAVE_LIBACL) + TARGET_LINK_LIBRARIES(bsdtar_test ${ACL_LIBRARY}) + ENDIF(HAVE_LIBACL) + ENDIF(ENABLE_ACL) SET_PROPERTY(TARGET bsdtar_test PROPERTY COMPILE_DEFINITIONS LIST_H) # diff --git a/tar/test/test_option_acls.c b/tar/test/test_option_acls.c new file mode 100644 index 00000000..5c3fbfd1 --- /dev/null +++ b/tar/test/test_option_acls.c @@ -0,0 +1,471 @@ +/*- + * Copyright (c) 2017 Martin Matuska + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "test.h" +__FBSDID("$FreeBSD$"); + +#if HAVE_POSIX_ACL || HAVE_DARWIN_ACL +static const acl_perm_t acl_perms[] = { +#if HAVE_DARWIN_ACL + ACL_READ_DATA, + ACL_LIST_DIRECTORY, + ACL_WRITE_DATA, + ACL_ADD_FILE, + ACL_EXECUTE, + ACL_SEARCH, + ACL_DELETE, + ACL_APPEND_DATA, + ACL_ADD_SUBDIRECTORY, + ACL_DELETE_CHILD, + ACL_READ_ATTRIBUTES, + ACL_WRITE_ATTRIBUTES, + ACL_READ_EXTATTRIBUTES, + ACL_WRITE_EXTATTRIBUTES, + ACL_READ_SECURITY, + ACL_WRITE_SECURITY, + ACL_CHANGE_OWNER, + ACL_SYNCHRONIZE +#else /* !HAVE_DARWIN_ACL */ + ACL_EXECUTE, + ACL_WRITE, + ACL_READ, +#if HAVE_FREEBSD_NFS4_ACL + ACL_READ_DATA, + ACL_LIST_DIRECTORY, + ACL_WRITE_DATA, + ACL_ADD_FILE, + ACL_APPEND_DATA, + ACL_ADD_SUBDIRECTORY, + ACL_READ_NAMED_ATTRS, + ACL_WRITE_NAMED_ATTRS, + ACL_DELETE_CHILD, + ACL_READ_ATTRIBUTES, + ACL_WRITE_ATTRIBUTES, + ACL_DELETE, + ACL_READ_ACL, + ACL_WRITE_ACL, + ACL_WRITE_OWNER, + ACL_SYNCHRONIZE +#endif /* HAVE_FREEBSD_NFS4_ACL */ +#endif /* !HAVE_DARWIN_ACL */ +}; +#if HAVE_DARWIN_ACL || HAVE_FREEBSD_NFS4_ACL +static const acl_flag_t acl_flags[] = { +#if HAVE_DARWIN_ACL + ACL_FLAG_DEFER_INHERIT, + ACL_FLAG_NO_INHERIT, + ACL_ENTRY_INHERITED, + ACL_ENTRY_FILE_INHERIT, + ACL_ENTRY_DIRECTORY_INHERIT, + ACL_ENTRY_LIMIT_INHERIT, + ACL_ENTRY_ONLY_INHERIT +#else /* HAVE_FREEBSD_NFS4_ACL */ + ACL_ENTRY_FILE_INHERIT, + ACL_ENTRY_DIRECTORY_INHERIT, + ACL_ENTRY_NO_PROPAGATE_INHERIT, + ACL_ENTRY_INHERIT_ONLY, + ACL_ENTRY_SUCCESSFUL_ACCESS, + ACL_ENTRY_FAILED_ACCESS, + ACL_ENTRY_INHERITED +#endif /* HAVE_FREEBSD_NFS4_ACL */ +}; +#endif /* HAVE_DARWIN_ACL || HAVE_FREEBSD_NFS4_ACL */ + +/* + * Compare two ACL entries on FreeBSD or on Mac OS X + */ +static int +compare_acl_entry(acl_entry_t ae_a, acl_entry_t ae_b, int is_nfs4) +{ + acl_tag_t tag_a, tag_b; + acl_permset_t permset_a, permset_b; + int perm_a, perm_b, perm_start, perm_end; + void *qual_a, *qual_b; +#if HAVE_FREEBSD_NFS4_ACL + acl_entry_type_t type_a, type_b; +#endif +#if HAVE_FREEBSD_NFS4_ACL || HAVE_DARWIN_ACL + acl_flagset_t flagset_a, flagset_b; + int flag_a, flag_b; +#endif + int i, r; + + + /* Compare ACL tag */ + r = acl_get_tag_type(ae_a, &tag_a); + failure("acl_get_tag_type() error: %s", strerror(errno)); + if (assertEqualInt(r, 0) == 0) + return (-1); + r = acl_get_tag_type(ae_b, &tag_b); + failure("acl_get_tag_type() error: %s", strerror(errno)); + if (assertEqualInt(r, 0) == 0) + return (-1); + if (tag_a != tag_b) + return (0); + + /* Compare ACL qualifier */ +#if HAVE_DARWIN_ACL + if (tag_a == ACL_EXTENDED_ALLOW || tag_b == ACL_EXTENDED_DENY) +#else + if (tag_a == ACL_USER || tag_a == ACL_GROUP) +#endif + { + qual_a = acl_get_qualifier(ae_a); + failure("acl_get_qualifier() error: %s", strerror(errno)); + if (assert(qual_a != NULL) == 0) + return (-1); + qual_b = acl_get_qualifier(ae_b); + failure("acl_get_qualifier() error: %s", strerror(errno)); + if (assert(qual_b != NULL) == 0) { + acl_free(qual_a); + return (-1); + } +#if HAVE_DARWIN_ACL + if (memcmp(((guid_t *)qual_a)->g_guid, + ((guid_t *)qual_b)->g_guid, KAUTH_GUID_SIZE) != 0) +#else + if ((tag_a == ACL_USER && + (*(uid_t *)qual_a != *(uid_t *)qual_b)) || + (tag_a == ACL_GROUP && + (*(gid_t *)qual_a != *(gid_t *)qual_b))) +#endif + { + acl_free(qual_a); + acl_free(qual_b); + return (0); + } + acl_free(qual_a); + acl_free(qual_b); + } + +#if HAVE_FREEBSD_NFS4_ACL + if (is_nfs4) { + /* Compare NFS4 ACL type */ + r = acl_get_entry_type_np(ae_a, &type_a); + failure("acl_get_entry_type_np() error: %s", strerror(errno)); + if (assertEqualInt(r, 0) == 0) + return (-1); + r = acl_get_entry_type_np(ae_b, &type_b); + failure("acl_get_entry_type_np() error: %s", strerror(errno)); + if (assertEqualInt(r, 0) == 0) + return (-1); + if (type_a != type_b) + return (0); + } +#endif + + /* Compare ACL perms */ + r = acl_get_permset(ae_a, &permset_a); + failure("acl_get_permset() error: %s", strerror(errno)); + if (assertEqualInt(r, 0) == 0) + return (-1); + r = acl_get_permset(ae_b, &permset_b); + failure("acl_get_permset() error: %s", strerror(errno)); + if (assertEqualInt(r, 0) == 0) + return (-1); + + perm_start = 0; + perm_end = (int)(sizeof(acl_perms) / sizeof(acl_perms[0])); +#if HAVE_FREEBSD_NFS4_ACL + if (is_nfs4) + perm_start = 3; + else + perm_end = 3; +#endif + /* Cycle through all perms and compare their value */ + for (i = perm_start; i < perm_end; i++) { +#if HAVE_LIBACL + perm_a = acl_get_perm(permset_a, acl_perms[i]); + perm_b = acl_get_perm(permset_b, acl_perms[i]); +#else + perm_a = acl_get_perm_np(permset_a, acl_perms[i]); + perm_b = acl_get_perm_np(permset_b, acl_perms[i]); +#endif + if (perm_a == -1 || perm_b == -1) + return (-1); + if (perm_a != perm_b) + return (0); + } + +#if HAVE_FREEBSD_NFS4_ACL || HAVE_DARWIN_ACL + if (is_nfs4) { + r = acl_get_flagset_np(ae_a, &flagset_a); + failure("acl_get_flagset_np() error: %s", strerror(errno)); + if (assertEqualInt(r, 0) == 0) + return (-1); + r = acl_get_flagset_np(ae_b, &flagset_b); + failure("acl_get_flagset_np() error: %s", strerror(errno)); + if (assertEqualInt(r, 0) == 0) + return (-1); + /* Cycle through all flags and compare their status */ + for (i = 0; i < (int)(sizeof(acl_flags) / sizeof(acl_flags[0])); + i++) { + flag_a = acl_get_flag_np(flagset_a, acl_flags[i]); + flag_b = acl_get_flag_np(flagset_b, acl_flags[i]); + if (flag_a == -1 || flag_b == -1) + return (-1); + if (flag_a != flag_b) + return (0); + } + } +#else /* HAVE_FREEBSD_NFS4_ACL || HAVE_DARWIN_ACL*/ + (void)is_nfs4; /* UNUSED */ +#endif + return (1); +} +#endif /* HAVE_POSIX_ACL || HAVE_DARWIN_ACL */ + +#if HAVE_SUN_ACL || HAVE_DARWIN_ACL || HAVE_POSIX_ACL +/* + * Clear default ACLs or inheritance flags + */ +static void +clear_inheritance_flags(const char *path, int type) +{ + switch (type) { + case ARCHIVE_TEST_ACL_TYPE_POSIX1E: +#if HAVE_POSIX_ACL + acl_delete_def_file(path); +#else + /* Solaris */ + setTestAcl(path); +#endif + break; + case ARCHIVE_TEST_ACL_TYPE_NFS4: +#if HAVE_NFS4_ACL + setTestAcl(path); +#endif + break; + default: + (void)path; /* UNUSED */ + break; + } +} + +static int +compare_acls(const char *path_a, const char *path_b) +{ + int ret = 1; + int is_nfs4 = 0; +#if HAVE_SUN_ACL + void *acl_a, *acl_b; + int aclcnt_a, aclcnt_b; + aclent_t *aclent_a, *aclent_b; + ace_t *ace_a, *ace_b; + int e; +#else + acl_t acl_a, acl_b; + acl_entry_t aclent_a, aclent_b; + int a, b, r; +#endif + + acl_a = NULL; + acl_b = NULL; +#if HAVE_SUN_ACL + acl_a = sunacl_get(GETACL, &aclcnt_a, 0, path_a); + if (acl_a == NULL) { +#if HAVE_SUN_NFS4_ACL + is_nfs4 = 1; + acl_a = sunacl_get(ACE_GETACL, &aclcnt_a, 0, path_a); +#endif + failure("acl_get() error: %s", strerror(errno)); + if (assert(acl_a != NULL) == 0) + return (-1); +#if HAVE_SUN_NFS4_ACL + acl_b = sunacl_get(ACE_GETACL, &aclcnt_b, 0, path_b); +#endif + } else + acl_b = sunacl_get(GETACL, &aclcnt_b, 0, path_b); + if (acl_b == NULL && (errno == ENOSYS || errno == ENOTSUP)) { + free(acl_a); + return (0); + } + failure("acl_get() error: %s", strerror(errno)); + if (assert(acl_b != NULL) == 0) { + free(acl_a); + return (-1); + } + + if (aclcnt_a != aclcnt_b) { + ret = 0; + goto exit_free; + } + + for (e = 0; e < aclcnt_a; e++) { + if (!is_nfs4) { + aclent_a = &((aclent_t *)acl_a)[e]; + aclent_b = &((aclent_t *)acl_b)[e]; + if (aclent_a->a_type != aclent_b->a_type || + aclent_a->a_id != aclent_b->a_id || + aclent_a->a_perm != aclent_b->a_perm) { + ret = 0; + goto exit_free; + } + } +#if HAVE_SUN_NFS4_ACL + else { + ace_a = &((ace_t *)acl_a)[e]; + ace_b = &((ace_t *)acl_b)[e]; + if (ace_a->a_who != ace_b->a_who || + ace_a->a_access_mask != ace_b->a_access_mask || + ace_a->a_flags != ace_b->a_flags || + ace_a->a_type != ace_b->a_type) { + ret = 0; + goto exit_free; + } + } +#endif + } +#else /* !HAVE_SUN_ACL */ +#if HAVE_DARWIN_ACL + is_nfs4 = 1; + acl_a = acl_get_file(path_a, ACL_TYPE_EXTENDED); +#elif HAVE_FREEBSD_NFS4_ACL + acl_a = acl_get_file(path_a, ACL_TYPE_NFS4); + if (acl_a != NULL) + is_nfs4 = 1; +#endif +#if !HAVE_DARWIN_ACL + if (acl_a == NULL) + acl_a = acl_get_file(path_a, ACL_TYPE_ACCESS); +#endif + failure("acl_get_file() error: %s (%s)", path_a, strerror(errno)); + if (assert(acl_a != NULL) == 0) + return (-1); +#if HAVE_DARWIN_ACL + acl_b = acl_get_file(path_b, ACL_TYPE_EXTENDED); +#elif HAVE_FREEBSD_NFS4_ACL + acl_b = acl_get_file(path_b, ACL_TYPE_NFS4); +#endif +#if !HAVE_DARWIN_ACL + if (acl_b == NULL) { +#if HAVE_FREEBSD_NFS4_ACL + if (is_nfs4) { + acl_free(acl_a); + return (0); + } +#endif + acl_b = acl_get_file(path_b, ACL_TYPE_ACCESS); + } + failure("acl_get_file() error: %s (%s)", path_b, strerror(errno)); + if (assert(acl_b != NULL) == 0) { + acl_free(acl_a); + return (-1); + } +#endif + a = acl_get_entry(acl_a, ACL_FIRST_ENTRY, &aclent_a); + if (a == -1) { + ret = 0; + goto exit_free; + } + b = acl_get_entry(acl_b, ACL_FIRST_ENTRY, &aclent_b); + if (b == -1) { + ret = 0; + goto exit_free; + } +#if HAVE_DARWIN_ACL + while (a == 0 && b == 0) +#else /* FreeBSD, Linux */ + while (a == 1 && b == 1) +#endif + { + r = compare_acl_entry(aclent_a, aclent_b, is_nfs4); + if (r != 1) { + ret = r; + goto exit_free; + } + a = acl_get_entry(acl_a, ACL_NEXT_ENTRY, &aclent_a); + b = acl_get_entry(acl_b, ACL_NEXT_ENTRY, &aclent_b); + } + /* Entry count must match */ + if (a != b) + ret = 0; +#endif /* !HAVE_SUN_ACL */ +exit_free: +#if HAVE_SUN_ACL + free(acl_a); + free(acl_b); +#else + acl_free(acl_a); + acl_free(acl_b); +#endif + return (ret); +} +#endif /* HAVE_SUN_ACL || HAVE_DARWIN_ACL || HAVE_POSIX_ACL */ + +DEFINE_TEST(test_option_acls) +{ +#if !HAVE_SUN_ACL && !HAVE_DARWIN_ACL && !HAVE_POSIX_ACL + skipping("ACLs are not supported on this platform"); +#else /* HAVE_SUN_ACL || HAVE_DARWIN_ACL || HAVE_POSIX_ACL */ + int acltype, r; + + assertMakeFile("f", 0644, "a"); + acltype = setTestAcl("f"); + if (acltype == 0) { + skipping("Can't write ACLs on the filesystem"); + return; + } + + /* Archive it with acls */ + r = systemf("%s -c --no-mac-metadata --acls -f acls.tar f >acls.out 2>acls.err", testprog); + assertEqualInt(r, 0); + + /* Archive it without acls */ + r = systemf("%s -c --no-mac-metadata --no-acls -f noacls.tar f >noacls.out 2>noacls.err", testprog); + assertEqualInt(r, 0); + + /* Extract acls with acls */ + assertMakeDir("acls_acls", 0755); + clear_inheritance_flags("acls_acls", acltype); + r = systemf("%s -x -C acls_acls --no-same-permissions --acls -f acls.tar >acls_acls.out 2>acls_acls.err", testprog); + assertEqualInt(r, 0); + r = compare_acls("f", "acls_acls/f"); + assertEqualInt(r, 1); + + /* Extractl acls without acls */ + assertMakeDir("acls_noacls", 0755); + clear_inheritance_flags("acls_noacls", acltype); + r = systemf("%s -x -C acls_noacls -p --no-acls -f acls.tar >acls_noacls.out 2>acls_noacls.err", testprog); + assertEqualInt(r, 0); + r = compare_acls("f", "acls_noacls/f"); + assertEqualInt(r, 0); + + /* Extract noacls with acls flag */ + assertMakeDir("noacls_acls", 0755); + clear_inheritance_flags("noacls_acls", acltype); + r = systemf("%s -x -C noacls_acls --no-same-permissions --acls -f noacls.tar >noacls_acls.out 2>noacls_acls.err", testprog); + assertEqualInt(r, 0); + r = compare_acls("f", "noacls_acls/f"); + assertEqualInt(r, 0); + + /* Extract noacls with noacls */ + assertMakeDir("noacls_noacls", 0755); + clear_inheritance_flags("noacls_noacls", acltype); + r = systemf("%s -x -C noacls_noacls -p --no-acls -f noacls.tar >noacls_noacls.out 2>noacls_noacls.err", testprog); + assertEqualInt(r, 0); + r = compare_acls("f", "noacls_noacls/f"); + assertEqualInt(r, 0); +#endif /* HAVE_SUN_ACL || HAVE_DARWIN_ACL || HAVE_POSIX_ACL */ +} diff --git a/test_utils/test_common.h b/test_utils/test_common.h index 1e5c1fec..00780541 100644 --- a/test_utils/test_common.h +++ b/test_utils/test_common.h @@ -73,6 +73,12 @@ #include <unistd.h> #endif #include <wchar.h> +#ifdef HAVE_ACL_LIBACL_H +#include <acl/libacl.h> +#endif +#ifdef HAVE_SYS_ACL_H +#include <sys/acl.h> +#endif #ifdef HAVE_WINDOWS_H #include <windows.h> #endif @@ -155,6 +161,9 @@ #define HAVE_NFS4_ACL 1 #endif +#define ARCHIVE_TEST_ACL_TYPE_POSIX1E 1 +#define ARCHIVE_TEST_ACL_TYPE_NFS4 2 + /* * Redefine DEFINE_TEST for use in defining the test functions. */ @@ -363,9 +372,17 @@ int canXz(void); /* Return true if this filesystem can handle nodump flags. */ int canNodump(void); +/* Set test ACLs */ +int setTestAcl(const char *path); + /* Return true if the file has large i-node number(>0xffffffff). */ int is_LargeInode(const char *); +#if HAVE_SUN_ACL +/* Fetch ACLs on Solaris using acl() or facl() */ +void *sunacl_get(int cmd, int *aclcnt, int fd, const char *path); +#endif + /* Suck file into string allocated via malloc(). Call free() when done. */ /* Supports printf-style args: slurpfile(NULL, "%s/myfile", refdir); */ char *slurpfile(size_t *, const char *fmt, ...); diff --git a/test_utils/test_main.c b/test_utils/test_main.c index ec2fbfed..86ab5f1a 100644 --- a/test_utils/test_main.c +++ b/test_utils/test_main.c @@ -56,6 +56,20 @@ #include <stdarg.h> #include <time.h> +/* ACL support */ +#ifdef HAVE_ACL_LIBACL_H +#include <acl/libacl.h> +#endif +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_SYS_ACL_H +#include <sys/acl.h> +#endif +#if HAVE_DARWIN_ACL +#include <membership.h> +#endif + /* * * Windows support routines @@ -2422,6 +2436,227 @@ canNodump(void) return (0); } +#if HAVE_SUN_ACL +/* Fetch ACLs on Solaris using acl() or facl() */ +void * +sunacl_get(int cmd, int *aclcnt, int fd, const char *path) +{ + int cnt, cntcmd; + size_t size; + void *aclp; + + if (cmd == GETACL) { + cntcmd = GETACLCNT; + size = sizeof(aclent_t); + } +#if HAVE_SUN_NFS4_ACL + else if (cmd == ACE_GETACL) { + cntcmd = ACE_GETACLCNT; + size = sizeof(ace_t); + } +#endif + else { + errno = EINVAL; + *aclcnt = -1; + return (NULL); + } + + aclp = NULL; + cnt = -2; + while (cnt == -2 || (cnt == -1 && errno == ENOSPC)) { + if (path != NULL) + cnt = acl(path, cntcmd, 0, NULL); + else + cnt = facl(fd, cntcmd, 0, NULL); + + if (cnt > 0) { + if (aclp == NULL) + aclp = malloc(cnt * size); + else + aclp = realloc(NULL, cnt * size); + if (aclp != NULL) { + if (path != NULL) + cnt = acl(path, cmd, cnt, aclp); + else + cnt = facl(fd, cmd, cnt, aclp); + } + } else { + if (aclp != NULL) { + free(aclp); + aclp = NULL; + } + break; + } + } + + *aclcnt = cnt; + return (aclp); +} +#endif /* HAVE_SUN_ACL */ + +/* + * Set test ACLs on a path + * Return values: + * 0: error setting ACLs + * ARCHIVE_TEST_ACL_TYPE_POSIX1E: POSIX.1E ACLs have been set + * ARCHIVE_TEST_ACL_TYPE_NFS4: NFSv4 or extended ACLs have been set + */ +int +setTestAcl(const char *path) +{ +#if HAVE_POSIX_ACL || HAVE_NFS4_ACL + int r = 1; +#if !HAVE_SUN_ACL + acl_t acl; +#endif +#if HAVE_POSIX_ACL /* Linux, FreeBSD POSIX.1e */ + const char *acltext_posix1e = "user:1:rw-," + "group:15:r-x," + "user::rwx," + "group::rwx," + "other::r-x," + "mask::rwx"; +#elif HAVE_SUN_ACL /* Solaris POSIX.1e */ + aclent_t aclp_posix1e[] = { + { USER_OBJ, -1, 4 | 2 | 1 }, + { USER, 1, 4 | 2 }, + { GROUP_OBJ, -1, 4 | 2 | 1 }, + { GROUP, 15, 4 | 1 }, + { CLASS_OBJ, -1, 4 | 2 | 1 }, + { OTHER_OBJ, -1, 4 | 2 | 1 } + }; +#endif +#if HAVE_FREEBSD_NFS4_ACL /* FreeBSD NFS4 */ + const char *acltext_nfs4 = "user:1:rwpaRcs::allow:1," + "group:15:rxaRcs::allow:15," + "owner@:rwpxaARWcCos::allow," + "group@:rwpxaRcs::allow," + "everyone@:rxaRcs::allow"; +#elif HAVE_SUN_NFS4_ACL /* Solaris NFS4 */ + ace_t aclp_nfs4[] = { + { 1, ACE_READ_DATA | ACE_WRITE_DATA | ACE_APPEND_DATA | + ACE_READ_ATTRIBUTES | ACE_READ_NAMED_ATTRS | ACE_READ_ACL | + ACE_SYNCHRONIZE, 0, ACE_ACCESS_ALLOWED_ACE_TYPE }, + { 15, ACE_READ_DATA | ACE_EXECUTE | ACE_READ_ATTRIBUTES | + ACE_READ_NAMED_ATTRS | ACE_READ_ACL | ACE_SYNCHRONIZE, + ACE_IDENTIFIER_GROUP, ACE_ACCESS_ALLOWED_ACE_TYPE }, + { -1, ACE_READ_DATA | ACE_WRITE_DATA | ACE_APPEND_DATA | + ACE_EXECUTE | ACE_READ_ATTRIBUTES | ACE_WRITE_ATTRIBUTES | + ACE_READ_NAMED_ATTRS | ACE_WRITE_NAMED_ATTRS | + ACE_READ_ACL | ACE_WRITE_ACL | ACE_WRITE_OWNER | ACE_SYNCHRONIZE, + ACE_OWNER, ACE_ACCESS_ALLOWED_ACE_TYPE }, + { -1, ACE_READ_DATA | ACE_WRITE_DATA | ACE_APPEND_DATA | + ACE_EXECUTE | ACE_READ_ATTRIBUTES | ACE_READ_NAMED_ATTRS | + ACE_READ_ACL | ACE_SYNCHRONIZE, ACE_GROUP | ACE_IDENTIFIER_GROUP, + ACE_ACCESS_ALLOWED_ACE_TYPE }, + { -1, ACE_READ_DATA | ACE_EXECUTE | ACE_READ_ATTRIBUTES | + ACE_READ_NAMED_ATTRS | ACE_READ_ACL | ACE_SYNCHRONIZE, + ACE_EVERYONE, ACE_ACCESS_ALLOWED_ACE_TYPE } + }; +#elif HAVE_DARWIN_ACL /* Mac OS X */ + acl_entry_t aclent; + acl_permset_t permset; + const uid_t uid = 1; + uuid_t uuid; + int i; + const acl_perm_t acl_perms[] = { + ACL_READ_DATA, + ACL_WRITE_DATA, + ACL_APPEND_DATA, + ACL_EXECUTE, + ACL_READ_ATTRIBUTES, + ACL_READ_EXTATTRIBUTES, + ACL_READ_SECURITY, +#if HAVE_DECL_ACL_SYNCHRONIZE + ACL_SYNCHRONIZE +#endif + }; +#endif /* HAVE_DARWIN_ACL */ + +#if HAVE_FREEBSD_NFS4_ACL + acl = acl_from_text(acltext_nfs4); + failure("acl_from_text() error: %s", strerror(errno)); + if (assert(acl != NULL) == 0) + return (0); +#elif HAVE_DARWIN_ACL + acl = acl_init(1); + failure("acl_init() error: %s", strerror(errno)); + if (assert(acl != NULL) == 0) + return (0); + r = acl_create_entry(&acl, &aclent); + failure("acl_create_entry() error: %s", strerror(errno)); + if (assertEqualInt(r, 0) == 0) + goto testacl_free; + r = acl_set_tag_type(aclent, ACL_EXTENDED_ALLOW); + failure("acl_set_tag_type() error: %s", strerror(errno)); + if (assertEqualInt(r, 0) == 0) + goto testacl_free; + r = acl_get_permset(aclent, &permset); + failure("acl_get_permset() error: %s", strerror(errno)); + if (assertEqualInt(r, 0) == 0) + goto testacl_free; + for (i = 0; i < (int)(sizeof(acl_perms) / sizeof(acl_perms[0])); i++) { + r = acl_add_perm(permset, acl_perms[i]); + failure("acl_add_perm() error: %s", strerror(errno)); + if (assertEqualInt(r, 0) == 0) + goto testacl_free; + } + r = acl_set_permset(aclent, permset); + failure("acl_set_permset() error: %s", strerror(errno)); + if (assertEqualInt(r, 0) == 0) + goto testacl_free; + r = mbr_identifier_to_uuid(ID_TYPE_UID, &uid, sizeof(uid_t), uuid); + failure("mbr_identifier_to_uuid() error: %s", strerror(errno)); + if (assertEqualInt(r, 0) == 0) + goto testacl_free; + r = acl_set_qualifier(aclent, uuid); + failure("acl_set_qualifier() error: %s", strerror(errno)); + if (assertEqualInt(r, 0) == 0) + goto testacl_free; +#endif /* HAVE_DARWIN_ACL */ + +#if HAVE_NFS4_ACL +#if HAVE_FREEBSD_NFS4_ACL + r = acl_set_file(path, ACL_TYPE_NFS4, acl); + acl_free(acl); +#elif HAVE_SUN_NFS4_ACL + r = acl(path, ACE_SETACL, + (int)(sizeof(aclp_nfs4)/sizeof(aclp_nfs4[0])), aclp_nfs4); +#elif HAVE_DARWIN_ACL + r = acl_set_file(path, ACL_TYPE_EXTENDED, acl); + acl_free(acl); +#endif + if (r == 0) + return (ARCHIVE_TEST_ACL_TYPE_NFS4); +#endif /* HAVE_NFS4_ACL */ + +#if HAVE_POSIX_ACL || HAVE_SUN_ACL +#if HAVE_POSIX_ACL + acl = acl_from_text(acltext_posix1e); + failure("acl_from_text() error: %s", strerror(errno)); + if (assert(acl != NULL) == 0) + return (0); + + r = acl_set_file(path, ACL_TYPE_ACCESS, acl); + acl_free(acl); +#elif HAVE_SUN_ACL + r = acl(path, SETACL, + (int)(sizeof(aclp_posix1e)/sizeof(aclp_posix1e[0])), aclp_posix1e); +#endif + if (r == 0) + return (ARCHIVE_TEST_ACL_TYPE_POSIX1E); + else + return (0); +#endif /* HAVE_POSIX_ACL || HAVE_SUN_ACL */ +#if HAVE_DARWIN_ACL +testacl_free: + acl_free(acl); +#endif +#endif /* HAVE_POSIX_ACL || HAVE_NFS4_ACL */ + (void)path; /* UNUSED */ + return (0); +} + /* * Sleep as needed; useful for verifying disk timestamp changes by * ensuring that the wall-clock time has actually changed before we |