From: Martin Matuska Date: Sun, 29 Jan 2017 14:51:02 +0000 (+0100) Subject: Add NFSv4 ACL support for Mac OS X X-Git-Tag: v3.3.0~33 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9f43a7d60fd99cc5a8f6420b6c692bb137f85bb8;p=thirdparty%2Flibarchive.git Add NFSv4 ACL support for Mac OS X Mac OS X supports user and group NFSv4-style ACLs only (extended ACLs). File-mode ACLs (owner@, group@ and everyone@) are not supported. Behavior on Mac OS X: - libarchive does not store GUID of Mac OS X extended ACLs. Only uid or gid (and the corresponding user or group name) are stored. - When extracting an archive entry that has mac_metadata, NFSv4 ACLs are not written to disk (mac_metadata already contains ACLs) - When writing ACLs to disk from an archive entry with NFSv4 ACLs owner@, group@ and everyone@ ACLs are ignored. User and group ids are converted to a GUID (this may lead to a fabricated GUID if the user or group ID is not present on the system) - When reading ACL from disk and there is at least one user or group extended ACL entry, owner@, group@ and everyone@ entries mirroring the file mode are added to the end of the entry's ACL. --- diff --git a/CMakeLists.txt b/CMakeLists.txt index bad694aba..cda1506f2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1610,6 +1610,9 @@ IF(ENABLE_ACL) # MacOS has an acl.h that isn't POSIX. It can be detected by # checking for ACL_USER CHECK_SYMBOL_EXISTS(ACL_USER "${INCLUDES}" HAVE_ACL_USER) + CHECK_C_SOURCE_COMPILES("#include +#include +int main(void) { return ACL_TYPE_EXTENDED; }" HAVE_ACL_TYPE_EXTENDED) # Solaris and derivates ACLs CHECK_LIBRARY_EXISTS(sec "acl_get" "" HAVE_LIBSEC) @@ -1641,6 +1644,7 @@ ELSE(ENABLE_ACL) SET(HAVE_ACL_SET_FILE FALSE) SET(HAVE_ACL_TYPE_NFS4 FALSE) SET(HAVE_ACL_USER FALSE) + SET(HAVE_ACL_TYPE_EXTENDED FALSE) SET(HAVE_ACL_GET FALSE) SET(HAVE_ACLENT_T FALSE) SET(HAVE_ACE_T FALSE) diff --git a/build/cmake/config.h.in b/build/cmake/config.h.in index cd87c94ed..ec64d9937 100644 --- a/build/cmake/config.h.in +++ b/build/cmake/config.h.in @@ -329,6 +329,9 @@ typedef uint64_t uintmax_t; /* True for FreeBSD with NFSv4 ACL support */ #cmakedefine HAVE_ACL_TYPE_NFS4 1 +/* True for MacOS ACL support */ +#cmakedefine HAVE_ACL_TYPE_EXTENDED 1 + /* True for systems with POSIX ACL support */ #cmakedefine HAVE_ACL_USER 1 diff --git a/configure.ac b/configure.ac index a2bce2cf9..0afb59cef 100644 --- a/configure.ac +++ b/configure.ac @@ -737,6 +737,13 @@ if test "x$enable_acl" != "xno"; then [], [#include ]) + # MacOS has ACL_TYPE_EXTENDED instead + AC_CHECK_DECL([ACL_TYPE_EXTENDED], + [AC_DEFINE(HAVE_ACL_TYPE_EXTENDED, 1, [True for MacOS ACL support])], + [], + [#include + #include ]) + # Solaris and derivates ACLs AC_CHECK_LIB([sec], [acl_get]) AC_CHECK_TYPES([aclent_t], [], [], [[#include ]]) diff --git a/libarchive/archive_platform.h b/libarchive/archive_platform.h index eb9d4bbe8..c9a960201 100644 --- a/libarchive/archive_platform.h +++ b/libarchive/archive_platform.h @@ -147,8 +147,12 @@ * acl_set_file(), and ACL_USER, we assume it has the rest of the * POSIX.1e draft functions used in archive_read_extract.c. */ -#if HAVE_SYS_ACL_H && HAVE_ACL_CREATE_ENTRY && HAVE_ACL_INIT && HAVE_ACL_SET_FILE && HAVE_ACL_USER +#if HAVE_SYS_ACL_H && HAVE_ACL_CREATE_ENTRY && HAVE_ACL_INIT && HAVE_ACL_SET_FILE +#if HAVE_ACL_USER #define HAVE_POSIX_ACL 1 +#elif HAVE_ACL_TYPE_EXTENDED +#define HAVE_DARWIN_ACL 1 +#endif #endif /* @@ -159,6 +163,11 @@ #define HAVE_SUN_ACL 1 #endif +/* Define if platform supports NFSv4 ACLs */ +#if (HAVE_POSIX_ACL && HAVE_ACL_TYPE_NFS4) || HAVE_SUN_ACL || HAVE_DARWIN_ACL +#define HAVE_NFS4_ACL 1 +#endif + /* * If we can't restore metadata using a file descriptor, then * for compatibility's sake, close files before trying to restore metadata. diff --git a/libarchive/archive_read_disk_entry_from_file.c b/libarchive/archive_read_disk_entry_from_file.c index 26f8fad14..47085cb7b 100644 --- a/libarchive/archive_read_disk_entry_from_file.c +++ b/libarchive/archive_read_disk_entry_from_file.c @@ -38,6 +38,11 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_disk_entry_from_file.c 2010 #ifdef HAVE_SYS_ACL_H #include #endif +#ifdef HAVE_DARWIN_ACL +#include +#include +#include +#endif #ifdef HAVE_SYS_EXTATTR_H #include #endif @@ -118,6 +123,15 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_disk_entry_from_file.c 2010 #define ACL_GET_PERM acl_get_perm_np #endif +/* NFSv4 platform ACL type */ +#if HAVE_SUN_ACL +#define ARCHIVE_PLATFORM_ACL_TYPE_NFS4 ACE_T +#elif HAVE_DARWIN_ACL +#define ARCHIVE_PLATFORM_ACL_TYPE_NFS4 ACL_TYPE_EXTENDED +#elif HAVE_ACL_TYPE_NFS4 +#define ARCHIVE_PLATFORM_ACL_TYPE_NFS4 ACL_TYPE_NFS4 +#endif + static int setup_acls(struct archive_read_disk *, struct archive_entry *, int *fd); static int setup_mac_metadata(struct archive_read_disk *, @@ -405,12 +419,19 @@ setup_mac_metadata(struct archive_read_disk *a, } #endif +#if HAVE_DARWIN_ACL +static int translate_guid(struct archive *, acl_entry_t, + int *, int *, const char **); + +static void add_trivial_nfs4_acl(struct archive_entry *); +#endif + #if HAVE_SUN_ACL static int sun_acl_is_trivial(acl_t *, mode_t, int *trivialp); #endif -#if HAVE_POSIX_ACL || HAVE_SUN_ACL +#if HAVE_POSIX_ACL || HAVE_NFS4_ACL static int translate_acl(struct archive_read_disk *a, struct archive_entry *entry, #if HAVE_SUN_ACL @@ -454,19 +475,20 @@ setup_acls(struct archive_read_disk *a, acl = NULL; -#if HAVE_ACL_TYPE_NFS4 || HAVE_SUN_ACL +#if HAVE_NFS4_ACL /* Try NFSv4 ACL first. */ if (*fd >= 0) #if HAVE_SUN_ACL + /* Solaris reads both POSIX.1e and NFSv4 ACL here */ facl_get(*fd, 0, &acl); #elif HAVE_ACL_GET_FD_NP - acl = acl_get_fd_np(*fd, ACL_TYPE_NFS4); + acl = acl_get_fd_np(*fd, ARCHIVE_PLATFORM_ACL_TYPE_NFS4); #else acl = acl_get_fd(*fd); #endif #if HAVE_ACL_GET_LINK_NP else if (!a->follow_symlinks) - acl = acl_get_link_np(accpath, ACL_TYPE_NFS4); + acl = acl_get_link_np(accpath, ARCHIVE_PLATFORM_ACL_TYPE_NFS4); #else else if ((!a->follow_symlinks) && (archive_entry_filetype(entry) == AE_IFLNK)) @@ -476,9 +498,10 @@ setup_acls(struct archive_read_disk *a, #endif else #if HAVE_SUN_ACL + /* Solaris reads both POSIX.1e and NFSv4 ACLs here */ acl_get(accpath, 0, &acl); #else - acl = acl_get_file(accpath, ACL_TYPE_NFS4); + acl = acl_get_file(accpath, ARCHIVE_PLATFORM_ACL_TYPE_NFS4); #endif @@ -513,11 +536,24 @@ setup_acls(struct archive_read_disk *a, "Couldn't translate NFSv4 ACLs: %s", accpath); #endif } +#if HAVE_DARWIN_ACL + /* + * Because Mac OS doesn't support owner@, group@ and everyone@ + * ACLs we need to add NFSv4 ACLs mirroring the file mode to + * the archive entry. Otherwise extraction on non-Mac platforms + * would lead to an invalid file mode. + */ + if (archive_entry_acl_count(entry, + ARCHIVE_ENTRY_ACL_TYPE_NFS4) > 0) + add_trivial_nfs4_acl(entry); +#endif return (r); } -#endif /* HAVE_ACL_TYPE_NFS4 || HAVE_SUN_ACL */ +#endif /* HAVE_NFS4_ACL */ + +#if HAVE_POSIX_ACL + /* This code path is skipped on MacOS and Solaris */ -#if !HAVE_SUN_ACL /* Retrieve access ACL from file. */ if (*fd >= 0) acl = acl_get_fd(*fd); @@ -575,7 +611,7 @@ setup_acls(struct archive_read_disk *a, } } } -#endif /* !HAVE_SUN_ACL */ +#endif /* HAVE_POSIX_ACL */ return (ARCHIVE_OK); } @@ -604,6 +640,24 @@ static struct { {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACE_WRITE_ACL}, {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACE_WRITE_OWNER}, {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACE_SYNCHRONIZE} +#elif HAVE_DARWIN_ACL /* MacOS ACL permissions */ + {ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA}, + {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY}, + {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA}, + {ARCHIVE_ENTRY_ACL_ADD_FILE, ACL_ADD_FILE}, + {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE}, + {ARCHIVE_ENTRY_ACL_DELETE, ACL_DELETE}, + {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACL_APPEND_DATA}, + {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACL_ADD_SUBDIRECTORY}, + {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACL_DELETE_CHILD}, + {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES}, + {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES}, + {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACL_READ_EXTATTRIBUTES}, + {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACL_WRITE_EXTATTRIBUTES}, + {ARCHIVE_ENTRY_ACL_READ_ACL, ACL_READ_SECURITY}, + {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_SECURITY}, + {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_CHANGE_OWNER}, + {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE} #else /* POSIX.1e ACL permissions */ {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE}, {ARCHIVE_ENTRY_ACL_WRITE, ACL_WRITE}, @@ -626,10 +680,10 @@ static struct { {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_WRITE_OWNER}, {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE} #endif -#endif /* !HAVE_SUN_ACL */ +#endif /* !HAVE_SUN_ACL && !HAVE_DARWIN_ACL */ }; -#if HAVE_ACL_TYPE_NFS4 || HAVE_SUN_ACL +#if HAVE_NFS4_ACL /* * Translate system NFSv4 inheritance flags into libarchive internal structure */ @@ -637,7 +691,7 @@ static struct { int archive_inherit; int platform_inherit; } acl_inherit_map[] = { -#if HAVE_SUN_ACL +#if HAVE_SUN_ACL /* Solaris ACL inheritance flags */ {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACE_FILE_INHERIT_ACE}, {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACE_DIRECTORY_INHERIT_ACE}, {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACE_NO_PROPAGATE_INHERIT_ACE}, @@ -645,7 +699,13 @@ static struct { {ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, ACE_SUCCESSFUL_ACCESS_ACE_FLAG}, {ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, ACE_FAILED_ACCESS_ACE_FLAG}, {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACE_INHERITED_ACE} -#else /* !HAVE_SUN_ACL */ +#elif HAVE_DARWIN_ACL /* MacOS NFSv4 inheritance flags */ + {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACL_ENTRY_INHERITED}, + {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT}, + {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT}, + {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_LIMIT_INHERIT}, + {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_ONLY_INHERIT} +#else /* FreeBSD NFSv4 ACL inheritance flags */ {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT}, {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT}, {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_NO_PROPAGATE_INHERIT}, @@ -653,11 +713,140 @@ static struct { {ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, ACL_ENTRY_SUCCESSFUL_ACCESS}, {ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, ACL_ENTRY_FAILED_ACCESS}, {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACL_ENTRY_INHERITED} -#endif /* !HAVE_SUN_ACL */ +#endif /* !HAVE_SUN_ACL && !HAVE_DARWIN_ACL */ }; -#endif /* HAVE_ACL_TYPE_NFS4 || HAVE_SUN_ACL */ +#endif /* HAVE_NFS4_ACL */ + +#if HAVE_DARWIN_ACL +static int translate_guid(struct archive *a, acl_entry_t acl_entry, + int *ae_id, int *ae_tag, const char **ae_name) +{ + void *q; + uid_t ugid; + int r, idtype; + struct passwd *pwd; + struct group *grp; + + q = acl_get_qualifier(acl_entry); + if (q == NULL) + return (1); + r = mbr_uuid_to_id((const unsigned char *)q, &ugid, &idtype); + if (r != 0) + return (1); + if (idtype == ID_TYPE_UID) { + *ae_tag = ARCHIVE_ENTRY_ACL_USER; + pwd = getpwuuid(q); + if (pwd == NULL) { + *ae_id = ugid; + *ae_name = NULL; + } else { + *ae_id = pwd->pw_uid; + *ae_name = archive_read_disk_uname(a, *ae_id); + } + } else if (idtype == ID_TYPE_GID) { + *ae_tag = ARCHIVE_ENTRY_ACL_GROUP; + grp = getgruuid(q); + if (grp == NULL) { + *ae_id = ugid; + *ae_name = NULL; + } else { + *ae_id = grp->gr_gid; + *ae_name = archive_read_disk_gname(a, *ae_id); + } + } else + return (1); + return (0); +} -#if HAVE_SUN_ACL +/* + * Add trivial NFSv4 ACL entries from mode + */ +static void +add_trivial_nfs4_acl(struct archive_entry *entry) +{ + mode_t mode; + int i; + const int rperm = ARCHIVE_ENTRY_ACL_READ_DATA; + const int wperm = ARCHIVE_ENTRY_ACL_WRITE_DATA | + ARCHIVE_ENTRY_ACL_APPEND_DATA; + const int eperm = ARCHIVE_ENTRY_ACL_EXECUTE; + const int pubset = ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_READ_ACL | + ARCHIVE_ENTRY_ACL_SYNCHRONIZE; + const int ownset = pubset | ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_WRITE_ACL | + ARCHIVE_ENTRY_ACL_WRITE_OWNER; + + struct { + const int type; + const int tag; + int permset; + } tacl_entry[] = { + {ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_USER_OBJ, 0}, + {ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_USER_OBJ, 0}, + {ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_GROUP_OBJ, 0}, + {ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_USER_OBJ, ownset}, + {ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_GROUP_OBJ, pubset}, + {ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EVERYONE, pubset} + }; + + mode = archive_entry_mode(entry); + + /* Permissions for everyone@ */ + if (mode & 0004) + tacl_entry[5].permset |= rperm; + if (mode & 0002) + tacl_entry[5].permset |= wperm; + if (mode & 0001) + tacl_entry[5].permset |= eperm; + + /* Permissions for group@ */ + if (mode & 0040) + tacl_entry[4].permset |= rperm; + else if (mode & 0004) + tacl_entry[2].permset |= rperm; + if (mode & 0020) + tacl_entry[4].permset |= wperm; + else if (mode & 0002) + tacl_entry[2].permset |= wperm; + if (mode & 0010) + tacl_entry[4].permset |= eperm; + else if (mode & 0001) + tacl_entry[2].permset |= eperm; + + /* Permissions for owner@ */ + if (mode & 0400) { + tacl_entry[3].permset |= rperm; + if (!(mode & 0040) && (mode & 0004)) + tacl_entry[0].permset |= rperm; + } else if ((mode & 0040) || (mode & 0004)) + tacl_entry[1].permset |= rperm; + if (mode & 0200) { + tacl_entry[3].permset |= wperm; + if (!(mode & 0020) && (mode & 0002)) + tacl_entry[0].permset |= wperm; + } else if ((mode & 0020) || (mode & 0002)) + tacl_entry[1].permset |= wperm; + if (mode & 0100) { + tacl_entry[3].permset |= eperm; + if (!(mode & 0010) && (mode & 0001)) + tacl_entry[0].permset |= eperm; + } else if ((mode & 0010) || (mode & 0001)) + tacl_entry[1].permset |= eperm; + + for (i = 0; i < 6; i++) { + if (tacl_entry[i].permset != 0) { + archive_entry_acl_add_entry(entry, + tacl_entry[i].type, tacl_entry[i].permset, + tacl_entry[i].tag, -1, NULL); + } + } + + return; +} +#elif HAVE_SUN_ACL /* * Check if acl is trivial * This is a FreeBSD acl_is_trivial_np() implementation for Solaris @@ -810,7 +999,9 @@ sun_acl_is_trivial(acl_t *acl, mode_t mode, int *trivialp) *trivialp = 1; return (0); } +#endif /* HAVE_SUN_ACL */ +#if HAVE_SUN_ACL /* * Translate Solaris POSIX.1e and NFSv4 ACLs into libarchive internal ACL */ @@ -945,8 +1136,8 @@ translate_acl(struct archive_read_disk *a, } #else /* !HAVE_SUN_ACL */ /* - * Translate POSIX.1e (Linux) and FreeBSD (both POSIX.1e and NFSv4) - * ACLs into libarchive internal structure + * Translate POSIX.1e (Linux), FreeBSD (both POSIX.1e and NFSv4) and + * MacOS (NFSv4 only) ACLs into libarchive internal structure */ static int translate_acl(struct archive_read_disk *a, @@ -955,8 +1146,10 @@ translate_acl(struct archive_read_disk *a, acl_tag_t acl_tag; #if HAVE_ACL_TYPE_NFS4 acl_entry_type_t acl_type; - acl_flagset_t acl_flagset; int brand; +#endif +#if HAVE_ACL_TYPE_NFS4 || HAVE_DARWIN_ACL + acl_flagset_t acl_flagset; #endif acl_entry_t acl_entry; acl_permset_t acl_permset; @@ -964,7 +1157,6 @@ translate_acl(struct archive_read_disk *a, int r, s, ae_id, ae_tag, ae_perm; const char *ae_name; - #if HAVE_ACL_TYPE_NFS4 // FreeBSD "brands" ACLs as POSIX.1e or NFSv4 // Make sure the "brand" on this ACL is consistent @@ -1006,7 +1198,13 @@ translate_acl(struct archive_read_disk *a, "Failed to get first ACL entry"); return (ARCHIVE_WARN); } - while (s == 1) { + +#if HAVE_DARWIN_ACL + while (s == 0) +#else /* FreeBSD, Linux */ + while (s == 1) +#endif + { ae_id = -1; ae_name = NULL; ae_perm = 0; @@ -1017,6 +1215,7 @@ translate_acl(struct archive_read_disk *a, return (ARCHIVE_WARN); } switch (acl_tag) { +#if !HAVE_DARWIN_ACL /* FreeBSD, Linux */ case ACL_USER: ae_id = (int)*(uid_t *)acl_get_qualifier(acl_entry); ae_name = archive_read_disk_uname(&a->archive, ae_id); @@ -1044,16 +1243,39 @@ translate_acl(struct archive_read_disk *a, ae_tag = ARCHIVE_ENTRY_ACL_EVERYONE; break; #endif +#else /* HAVE_DARWIN_ACL */ + case ACL_EXTENDED_ALLOW: + entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW; + r = translate_guid(&a->archive, acl_entry, &ae_id, + &ae_tag, &ae_name); + break; + case ACL_EXTENDED_DENY: + entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DENY; + r = translate_guid(&a->archive, acl_entry, &ae_id, + &ae_tag, &ae_name); + break; +#endif /* HAVE_DARWIN_ACL */ default: /* Skip types that libarchive can't support. */ s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry); continue; } +#if HAVE_DARWIN_ACL + /* Skip if translate_guid() above failed */ + if (r != 0) { + s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry); + continue; + } +#endif + +#if !HAVE_DARWIN_ACL // XXX acl_type maps to allow/deny/audit/YYYY bits entry_acl_type = default_entry_acl_type; -#if HAVE_ACL_TYPE_NFS4 +#endif +#if HAVE_ACL_TYPE_NFS4 || HAVE_DARWIN_ACL if (default_entry_acl_type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) { +#if HAVE_ACL_TYPE_NFS4 /* * acl_get_entry_type_np() fails with non-NFSv4 ACLs */ @@ -1080,6 +1302,7 @@ translate_acl(struct archive_read_disk *a, "Invalid NFSv4 ACL entry type"); return (ARCHIVE_WARN); } +#endif /* HAVE_ACL_TYPE_NFS4 */ /* * Libarchive stores "flag" (NFSv4 inheritance bits) @@ -1104,7 +1327,7 @@ translate_acl(struct archive_read_disk *a, ae_perm |= acl_inherit_map[i].archive_inherit; } } -#endif +#endif /* HAVE_ACL_TYPE_NFS4 || HAVE_DARWIN_ACL */ if (acl_get_permset(acl_entry, &acl_permset) != 0) { archive_set_error(&a->archive, errno, @@ -1130,16 +1353,18 @@ translate_acl(struct archive_read_disk *a, ae_id, ae_name); s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry); +#if !HAVE_DARWIN_ACL if (s == -1) { archive_set_error(&a->archive, errno, "Failed to get next ACL entry"); return (ARCHIVE_WARN); } +#endif } return (ARCHIVE_OK); } #endif /* !HAVE_SUN_ACL */ -#else /* !HAVE_POSIX_ACL && !HAVE_SUN_ACL */ +#else /* !HAVE_POSIX_ACL && !HAVE_NFS4_ACL */ static int setup_acls(struct archive_read_disk *a, struct archive_entry *entry, int *fd) @@ -1149,7 +1374,7 @@ setup_acls(struct archive_read_disk *a, (void)fd; /* UNUSED */ return (ARCHIVE_OK); } -#endif /* !HAVE_POSIX_ACL && !HAVE_SUN_ACL */ +#endif /* !HAVE_POSIX_ACL && !HAVE_NFS4_ACL */ #if (HAVE_FGETXATTR && HAVE_FLISTXATTR && HAVE_LISTXATTR && \ HAVE_LLISTXATTR && HAVE_GETXATTR && HAVE_LGETXATTR) || \ diff --git a/libarchive/archive_write_disk_acl.c b/libarchive/archive_write_disk_acl.c index a20852665..311aebf03 100644 --- a/libarchive/archive_write_disk_acl.c +++ b/libarchive/archive_write_disk_acl.c @@ -34,6 +34,9 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_write_disk.c 201159 2009-12-29 0 #define _ACL_PRIVATE /* For debugging */ #include #endif +#if HAVE_DARWIN_ACL +#include +#endif #ifdef HAVE_ERRNO_H #include #endif @@ -43,7 +46,7 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_write_disk.c 201159 2009-12-29 0 #include "archive_acl_private.h" #include "archive_write_disk_private.h" -#if !HAVE_POSIX_ACL && !HAVE_SUN_ACL +#if !HAVE_POSIX_ACL && !HAVE_NFS4_ACL /* Default empty function body to satisfy mainline code. */ int archive_write_disk_set_acls(struct archive *a, int fd, const char *name, @@ -56,7 +59,15 @@ archive_write_disk_set_acls(struct archive *a, int fd, const char *name, return (ARCHIVE_OK); } -#else /* HAVE_POSIX_ACL || HAVE_SUN_ACL */ +#else /* HAVE_POSIX_ACL || HAVE_NFS4_ACL */ + +#if HAVE_SUN_ACL +#define ARCHIVE_PLATFORM_ACL_TYPE_NFS4 ACE_T +#elif HAVE_DARWIN_ACL +#define ARCHIVE_PLATFORM_ACL_TYPE_NFS4 ACL_TYPE_EXTENDED +#elif HAVE_ACL_TYPE_NFS4 +#define ARCHIVE_PLATFORM_ACL_TYPE_NFS4 ACL_TYPE_NFS4 +#endif static int set_acl(struct archive *, int fd, const char *, struct archive_acl *, @@ -67,19 +78,15 @@ archive_write_disk_set_acls(struct archive *a, int fd, const char *name, struct archive_acl *abstract_acl) { int ret = ARCHIVE_OK; -#if HAVE_SUN_ACL - const int acltype_nfs4 = ACE_T; -#elif HAVE_ACL_TYPE_NFS4 - const int acltype_nfs4 = ACL_TYPE_NFS4; -#endif +#if !HAVE_DARWIN_ACL if ((archive_acl_types(abstract_acl) & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) { #if HAVE_SUN_ACL /* Solaris writes POSIX.1e access and default ACLs together */ ret = set_acl(a, fd, name, abstract_acl, ACLENT_T, ARCHIVE_ENTRY_ACL_TYPE_POSIX1E, "posix1e"); -#else +#else /* HAVE_POSIX_ACL */ if ((archive_acl_types(abstract_acl) & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) { ret = set_acl(a, fd, name, abstract_acl, @@ -93,15 +100,19 @@ archive_write_disk_set_acls(struct archive *a, int fd, const char *name, ret = set_acl(a, fd, name, abstract_acl, ACL_TYPE_DEFAULT, ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, "default"); -#endif +#endif /* !HAVE_SUN_ACL */ + /* Simultaeous POSIX.1e and NFSv4 is not supported */ + return (ret); } -#if HAVE_ACL_TYPE_NFS4 || HAVE_SUN_ACL - else if ((archive_acl_types(abstract_acl) & +#endif /* !HAVE_DARWIN_ACL */ +#if HAVE_NFS4_ACL + if ((archive_acl_types(abstract_acl) & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) { - ret = set_acl(a, fd, name, abstract_acl, acltype_nfs4, + ret = set_acl(a, fd, name, abstract_acl, + ARCHIVE_PLATFORM_ACL_TYPE_NFS4, ARCHIVE_ENTRY_ACL_TYPE_NFS4, "nfs4"); } -#endif /* HAVE_ACL_TYPE_NFS4 || HAVE_SUN_ACL */ +#endif /* HAVE_NFS4_ACL */ return (ret); } @@ -130,6 +141,24 @@ static struct { {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACE_WRITE_ACL}, {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACE_WRITE_OWNER}, {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACE_SYNCHRONIZE} +#elif HAVE_DARWIN_ACL /* MacOS ACL permissions */ + {ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA}, + {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY}, + {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA}, + {ARCHIVE_ENTRY_ACL_ADD_FILE, ACL_ADD_FILE}, + {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE}, + {ARCHIVE_ENTRY_ACL_DELETE, ACL_DELETE}, + {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACL_APPEND_DATA}, + {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACL_ADD_SUBDIRECTORY}, + {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACL_DELETE_CHILD}, + {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES}, + {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES}, + {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACL_READ_EXTATTRIBUTES}, + {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACL_WRITE_EXTATTRIBUTES}, + {ARCHIVE_ENTRY_ACL_READ_ACL, ACL_READ_SECURITY}, + {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_SECURITY}, + {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_CHANGE_OWNER}, + {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE} #else /* POSIX.1e ACL permissions */ {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE}, {ARCHIVE_ENTRY_ACL_WRITE, ACL_WRITE}, @@ -152,10 +181,10 @@ static struct { {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_WRITE_OWNER}, {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE} #endif -#endif /* !HAVE_SUN_ACL */ +#endif /* !HAVE_SUN_ACL && !HAVE_DARWIN_ACL */ }; -#if HAVE_ACL_TYPE_NFS4 || HAVE_SUN_ACL +#if HAVE_NFS4_ACL /* * Translate system NFSv4 inheritance flags into libarchive internal structure */ @@ -163,7 +192,7 @@ static struct { int archive_inherit; int platform_inherit; } acl_inherit_map[] = { -#if HAVE_SUN_ACL +#if HAVE_SUN_ACL /* Solaris NFSv4 inheritance flags */ {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACE_FILE_INHERIT_ACE}, {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACE_DIRECTORY_INHERIT_ACE}, {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACE_NO_PROPAGATE_INHERIT_ACE}, @@ -171,7 +200,13 @@ static struct { {ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, ACE_SUCCESSFUL_ACCESS_ACE_FLAG}, {ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, ACE_FAILED_ACCESS_ACE_FLAG}, {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACE_INHERITED_ACE} -#else /* !HAVE_SUN_ACL */ +#elif HAVE_DARWIN_ACL /* MacOS NFSv4 inheritance flags */ + {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACL_ENTRY_INHERITED}, + {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT}, + {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT}, + {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_LIMIT_INHERIT}, + {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_ONLY_INHERIT} +#else /* FreeBSD NFSv4 ACL inheritance flags */ {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT}, {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT}, {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_NO_PROPAGATE_INHERIT}, @@ -179,9 +214,9 @@ static struct { {ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, ACL_ENTRY_SUCCESSFUL_ACCESS}, {ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, ACL_ENTRY_FAILED_ACCESS}, {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACL_ENTRY_INHERITED} -#endif /* !HAVE_SUN_ACL */ +#endif /* !HAVE_SUN_ACL && !HAVE_DARWIN_ACL */ }; -#endif /* HAVE_ACL_TYPE_NFS4 || HAVE_SUN_ACL */ +#endif /* HAVE_NFS4_ACL */ static int set_acl(struct archive *a, int fd, const char *name, @@ -197,13 +232,18 @@ set_acl(struct archive *a, int fd, const char *name, acl_t acl; acl_entry_t acl_entry; acl_permset_t acl_permset; +#if HAVE_ACL_TYPE_NFS4 || HAVE_DARWIN_ACL + acl_flagset_t acl_flagset; #endif +#endif /* HAVE_SUN_ACL */ #if HAVE_ACL_TYPE_NFS4 - acl_flagset_t acl_flagset; - int r; + int r; #endif int ret; int ae_type, ae_permset, ae_tag, ae_id; +#if HAVE_DARWIN_ACL + uuid_t ae_uuid; +#endif uid_t ae_uid; gid_t ae_gid; const char *ae_name; @@ -270,7 +310,18 @@ set_acl(struct archive *a, int fd, const char *name, aclent->a_type = 0; aclent->a_perm = 0; } -#else /* !HAVE_SUN_ACL */ +#else /* !HAVE_SUN_ACL */ +#if HAVE_DARWIN_ACL + /* + * Mac OS doesn't support NFSv4 ACLs for + * owner@, group@ and everyone@. + * We skip any of these ACLs found. + */ + if (ae_tag == ARCHIVE_ENTRY_ACL_USER_OBJ || + ae_tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ || + ae_tag == ARCHIVE_ENTRY_ACL_EVERYONE) + continue; +#endif if (acl_create_entry(&acl, &acl_entry) != 0) { archive_set_error(a, errno, "Failed to create a new ACL entry"); @@ -278,6 +329,19 @@ set_acl(struct archive *a, int fd, const char *name, goto exit_free; } #endif /* !HAVE_SUN_ACL */ +#if HAVE_DARWIN_ACL + switch (ae_type) { + case ARCHIVE_ENTRY_ACL_TYPE_ALLOW: + acl_set_tag_type(acl_entry, ACL_EXTENDED_ALLOW); + break; + case ARCHIVE_ENTRY_ACL_TYPE_DENY: + acl_set_tag_type(acl_entry, ACL_EXTENDED_DENY); + break; + default: + /* We don't support any other types on MacOS */ + continue; + } +#endif switch (ae_tag) { #if HAVE_SUN_ACL case ARCHIVE_ENTRY_ACL_USER: @@ -323,15 +387,32 @@ set_acl(struct archive *a, int fd, const char *name, break; #else /* !HAVE_SUN_ACL */ case ARCHIVE_ENTRY_ACL_USER: - acl_set_tag_type(acl_entry, ACL_USER); ae_uid = archive_write_disk_uid(a, ae_name, ae_id); +#if !HAVE_DARWIN_ACL /* FreeBSD, Linux */ + acl_set_tag_type(acl_entry, ACL_USER); acl_set_qualifier(acl_entry, &ae_uid); +#else /* MacOS */ + if (mbr_identifier_to_uuid(ID_TYPE_UID, &ae_uid, + sizeof(uid_t), ae_uuid) != 0) + continue; + if (acl_set_qualifier(acl_entry, &ae_uuid) != 0) + continue; +#endif /* HAVE_DARWIN_ACL */ break; case ARCHIVE_ENTRY_ACL_GROUP: - acl_set_tag_type(acl_entry, ACL_GROUP); ae_gid = archive_write_disk_gid(a, ae_name, ae_id); +#if !HAVE_DARWIN_ACL /* FreeBSD, Linux */ + acl_set_tag_type(acl_entry, ACL_GROUP); acl_set_qualifier(acl_entry, &ae_gid); +#else /* MacOS */ + if (mbr_identifier_to_uuid(ID_TYPE_GID, &ae_gid, + sizeof(gid_t), ae_uuid) != 0) + continue; + if (acl_set_qualifier(acl_entry, &ae_uuid) != 0) + continue; +#endif /* HAVE_DARWIN_ACL */ break; +#if !HAVE_DARWIN_ACL /* FreeBSD, Linux */ case ARCHIVE_ENTRY_ACL_USER_OBJ: acl_set_tag_type(acl_entry, ACL_USER_OBJ); break; @@ -344,11 +425,12 @@ set_acl(struct archive *a, int fd, const char *name, case ARCHIVE_ENTRY_ACL_OTHER: acl_set_tag_type(acl_entry, ACL_OTHER); break; -#if HAVE_ACL_TYPE_NFS4 +#if HAVE_ACL_TYPE_NFS4 /* FreeBSD only */ case ARCHIVE_ENTRY_ACL_EVERYONE: acl_set_tag_type(acl_entry, ACL_EVERYONE); break; #endif +#endif /* !HAVE_DARWIN_ACL */ #endif /* !HAVE_SUN_ACL */ default: archive_set_error(a, ARCHIVE_ERRNO_MISC, @@ -471,14 +553,16 @@ set_acl(struct archive *a, int fd, const char *name, } } -#if HAVE_ACL_TYPE_NFS4 || HAVE_SUN_ACL +#if HAVE_NFS4_ACL #if HAVE_SUN_ACL if (acl_type == ACE_T) -#else +#elif HAVE_DARWIN_ACL + if (acl_type == ACL_TYPE_EXTENDED) +#else /* FreeBSD */ if (acl_type == ACL_TYPE_NFS4) #endif { -#ifdef HAVE_POSIX_ACL +#if HAVE_POSIX_ACL || HAVE_DARWIN_ACL /* * acl_get_flagset_np() fails with non-NFSv4 ACLs */ @@ -494,7 +578,7 @@ set_acl(struct archive *a, int fd, const char *name, ret = ARCHIVE_FAILED; goto exit_free; } -#endif +#endif /* HAVE_POSIX_ACL || HAVE_DARWIN_ACL */ for (i = 0; i < (int)(sizeof(acl_inherit_map) /sizeof(acl_inherit_map[0])); ++i) { if (ae_permset & acl_inherit_map[i].archive_inherit) { #if HAVE_SUN_ACL @@ -508,11 +592,11 @@ set_acl(struct archive *a, int fd, const char *name, ret = ARCHIVE_FAILED; goto exit_free; } -#endif /* HAVE_SUN_ACLi */ +#endif /* HAVE_SUN_ACL */ } } } -#endif +#endif /* HAVE_NFS4_ACL */ #if HAVE_SUN_ACL e++; #endif @@ -567,4 +651,4 @@ exit_free: acl_free(acl); return (ret); } -#endif /* HAVE_POSIX_ACL || HAVE_SUN_ACL */ +#endif /* HAVE_POSIX_ACL || HAVE_NFS4_ACL */ diff --git a/libarchive/archive_write_disk_posix.c b/libarchive/archive_write_disk_posix.c index fabe6bcae..29d687bf2 100644 --- a/libarchive/archive_write_disk_posix.c +++ b/libarchive/archive_write_disk_posix.c @@ -1702,10 +1702,25 @@ _archive_write_disk_finish_entry(struct archive *_a) * ACLs that prevent attribute changes (including time). */ if (a->todo & TODO_ACLS) { - int r2 = archive_write_disk_set_acls(&a->archive, a->fd, - archive_entry_pathname(a->entry), - archive_entry_acl(a->entry)); + int r2; +#ifdef HAVE_DARWIN_ACL + /* + * On Mac OS, platform ACLs are stored also in mac_metadata by + * the operating system. If mac_metadata is present it takes + * precedence and we skip extracting libarchive NFSv4 ACLs + */ + const void *metadata; + size_t metadata_size; + metadata = archive_entry_mac_metadata(a->entry, &metadata_size); + if (metadata == NULL || metadata_size == 0) { +#endif + r2 = archive_write_disk_set_acls(&a->archive, a->fd, + archive_entry_pathname(a->entry), + archive_entry_acl(a->entry)); if (r2 < ret) ret = r2; +#ifdef HAVE_DARWIN_ACL + } +#endif } finish_metadata: @@ -2264,8 +2279,12 @@ _archive_write_disk_close(struct archive *_a) if (p->fixup & TODO_MODE_BASE) chmod(p->name, p->mode); if (p->fixup & TODO_ACLS) - archive_write_disk_set_acls(&a->archive, - -1, p->name, &p->acl); +#ifdef HAVE_DARWIN_ACL + if (p->mac_metadata == NULL || + p->mac_metadata_size == 0) +#endif + archive_write_disk_set_acls(&a->archive, + -1, p->name, &p->acl); if (p->fixup & TODO_FFLAGS) set_fflags_platform(a, -1, p->name, p->mode, p->fflags_set, 0); diff --git a/libarchive/test/test.h b/libarchive/test/test.h index dd1ee8fe5..58df1cbfb 100644 --- a/libarchive/test/test.h +++ b/libarchive/test/test.h @@ -125,8 +125,12 @@ * acl_set_file(), and ACL_USER, we assume it has the rest of the * POSIX.1e draft functions used in archive_read_extract.c. */ -#if HAVE_SYS_ACL_H && HAVE_ACL_CREATE_ENTRY && HAVE_ACL_INIT && HAVE_ACL_SET_FILE && HAVE_ACL_USER +#if HAVE_SYS_ACL_H && HAVE_ACL_CREATE_ENTRY && HAVE_ACL_INIT && HAVE_ACL_SET_FILE +#if HAVE_ACL_USER #define HAVE_POSIX_ACL 1 +#elif HAVE_ACL_TYPE_EXTENDED +#define HAVE_DARWIN_ACL 1 +#endif #endif /* @@ -137,6 +141,11 @@ #define HAVE_SUN_ACL 1 #endif +/* Define if platform supports NFSv4 ACLs */ +#if (HAVE_POSIX_ACL && HAVE_ACL_TYPE_NFS4) || HAVE_SUN_ACL || HAVE_DARWIN_ACL +#define HAVE_NFS4_ACL 1 +#endif + /* * Redefine DEFINE_TEST for use in defining the test functions. */ diff --git a/libarchive/test/test_acl_platform_nfs4.c b/libarchive/test/test_acl_platform_nfs4.c index 4d865f983..be2826100 100644 --- a/libarchive/test/test_acl_platform_nfs4.c +++ b/libarchive/test/test_acl_platform_nfs4.c @@ -26,13 +26,15 @@ #include "test.h" __FBSDID("$FreeBSD$"); -#if HAVE_SUN_ACL || HAVE_POSIX_ACL +#if HAVE_POSIX_ACL || HAVE_NFS4_ACL #define _ACL_PRIVATE #include +#if HAVE_DARWIN_ACL +#include +#endif #endif -#if HAVE_SUN_ACL || (HAVE_POSIX_ACL && HAVE_ACL_TYPE_NFS4) - +#if HAVE_NFS4_ACL struct myacl_t { int type; int permset; @@ -42,11 +44,12 @@ struct myacl_t { }; static struct myacl_t acls_reg[] = { +#if !HAVE_DARWIN_ACL /* For this test, we need the file owner to be able to read and write the ACL. */ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_READ_ACL | ARCHIVE_ENTRY_ACL_WRITE_ACL | ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS | ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ARCHIVE_ENTRY_ACL_USER_OBJ, -1, ""}, - +#endif /* An entry for each type. */ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE, ARCHIVE_ENTRY_ACL_USER, 108, "user108" }, @@ -88,16 +91,53 @@ static struct myacl_t acls_reg[] = { // ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" }, { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE, ARCHIVE_ENTRY_ACL_GROUP, 136, "group136" }, +#if !HAVE_DARWIN_ACL { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE, ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" }, { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE, ARCHIVE_ENTRY_ACL_EVERYONE, -1, "" } +#else /* MacOS - mode 0654 */ + { ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_EXECUTE, + ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" }, + { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, + ARCHIVE_ENTRY_ACL_READ_DATA | + ARCHIVE_ENTRY_ACL_WRITE_DATA | + ARCHIVE_ENTRY_ACL_APPEND_DATA | + ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_READ_ACL | + ARCHIVE_ENTRY_ACL_WRITE_ACL | + ARCHIVE_ENTRY_ACL_WRITE_OWNER | + ARCHIVE_ENTRY_ACL_SYNCHRONIZE, + ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" }, + { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, + ARCHIVE_ENTRY_ACL_READ_DATA | + ARCHIVE_ENTRY_ACL_EXECUTE | + ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_READ_ACL | + ARCHIVE_ENTRY_ACL_SYNCHRONIZE, + ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" }, + { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, + ARCHIVE_ENTRY_ACL_READ_DATA | + ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_READ_ACL | + ARCHIVE_ENTRY_ACL_SYNCHRONIZE, + ARCHIVE_ENTRY_ACL_EVERYONE, -1, "" } +#endif }; +static const int acls_reg_cnt = (int)(sizeof(acls_reg)/sizeof(acls_reg[0])); + static struct myacl_t acls_dir[] = { /* For this test, we need to be able to read and write the ACL. */ +#if !HAVE_DARWIN_ACL { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_READ_ACL, ARCHIVE_ENTRY_ACL_USER_OBJ, -1, ""}, +#endif /* An entry for each type. */ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, @@ -167,12 +207,47 @@ static struct myacl_t acls_dir[] = { ARCHIVE_ENTRY_ACL_USER, 501, "user501" }, { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ARCHIVE_ENTRY_ACL_GROUP, 502, "group502" }, +#if !HAVE_DARWIN_ACL { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" }, { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ARCHIVE_ENTRY_ACL_EVERYONE, -1, "" } +#else /* MacOS - mode 0654 */ + { ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_EXECUTE, + ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" }, + { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, + ARCHIVE_ENTRY_ACL_READ_DATA | + ARCHIVE_ENTRY_ACL_WRITE_DATA | + ARCHIVE_ENTRY_ACL_APPEND_DATA | + ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_READ_ACL | + ARCHIVE_ENTRY_ACL_WRITE_ACL | + ARCHIVE_ENTRY_ACL_WRITE_OWNER | + ARCHIVE_ENTRY_ACL_SYNCHRONIZE, + ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" }, + { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, + ARCHIVE_ENTRY_ACL_READ_DATA | + ARCHIVE_ENTRY_ACL_EXECUTE | + ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_READ_ACL | + ARCHIVE_ENTRY_ACL_SYNCHRONIZE, + ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" }, + { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, + ARCHIVE_ENTRY_ACL_READ_DATA | + ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_READ_ACL | + ARCHIVE_ENTRY_ACL_SYNCHRONIZE, + ARCHIVE_ENTRY_ACL_EVERYONE, -1, "" } +#endif }; +static const int acls_dir_cnt = (int)(sizeof(acls_dir)/sizeof(acls_dir[0])); + static void set_acls(struct archive_entry *ae, struct myacl_t *acls, int start, int end) { @@ -219,6 +294,24 @@ acl_permset_to_bitmap(acl_permset_t opaque_ps) {ACE_WRITE_ACL, ARCHIVE_ENTRY_ACL_WRITE_ACL}, {ACE_WRITE_OWNER, ARCHIVE_ENTRY_ACL_WRITE_OWNER}, {ACE_SYNCHRONIZE, ARCHIVE_ENTRY_ACL_SYNCHRONIZE} +#elif HAVE_DARWIN_ACL /* MacOS NFSv4 ACL permissions */ + {ACL_READ_DATA, ARCHIVE_ENTRY_ACL_READ_DATA}, + {ACL_LIST_DIRECTORY, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY}, + {ACL_WRITE_DATA, ARCHIVE_ENTRY_ACL_WRITE_DATA}, + {ACL_ADD_FILE, ARCHIVE_ENTRY_ACL_ADD_FILE}, + {ACL_EXECUTE, ARCHIVE_ENTRY_ACL_EXECUTE}, + {ACL_DELETE, ARCHIVE_ENTRY_ACL_DELETE}, + {ACL_APPEND_DATA, ARCHIVE_ENTRY_ACL_APPEND_DATA}, + {ACL_ADD_SUBDIRECTORY, ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY}, + {ACL_DELETE_CHILD, ARCHIVE_ENTRY_ACL_DELETE_CHILD}, + {ACL_READ_ATTRIBUTES, ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES}, + {ACL_WRITE_ATTRIBUTES, ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES}, + {ACL_READ_EXTATTRIBUTES, ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS}, + {ACL_WRITE_EXTATTRIBUTES, ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS}, + {ACL_READ_SECURITY, ARCHIVE_ENTRY_ACL_READ_ACL}, + {ACL_WRITE_SECURITY, ARCHIVE_ENTRY_ACL_WRITE_ACL}, + {ACL_CHANGE_OWNER, ARCHIVE_ENTRY_ACL_WRITE_OWNER}, + {ACL_SYNCHRONIZE, ARCHIVE_ENTRY_ACL_SYNCHRONIZE}, #else /* FreeBSD NFSv4 ACL permissions */ {ACL_EXECUTE, ARCHIVE_ENTRY_ACL_EXECUTE}, {ACL_WRITE, ARCHIVE_ENTRY_ACL_WRITE}, @@ -269,8 +362,13 @@ acl_flagset_to_bitmap(acl_flagset_t opaque_fs) {ACE_SUCCESSFUL_ACCESS_ACE_FLAG, ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS}, {ACE_FAILED_ACCESS_ACE_FLAG, ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS}, {ACE_INHERITED_ACE, ARCHIVE_ENTRY_ACL_ENTRY_INHERITED} -#else /* FreeBSD NFSv4 ACL inheritance flags */ +#elif HAVE_DARWIN_ACL /* MacOS NFSv4 ACL inheritance flags */ {ACL_ENTRY_INHERITED, ARCHIVE_ENTRY_ACL_ENTRY_INHERITED}, + {ACL_ENTRY_FILE_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT}, + {ACL_ENTRY_DIRECTORY_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT}, + {ACL_ENTRY_LIMIT_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT}, + {ACL_ENTRY_ONLY_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY} +#else /* FreeBSD NFSv4 ACL inheritance flags */ {ACL_ENTRY_FILE_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT}, {ACL_ENTRY_DIRECTORY_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT}, {ACL_ENTRY_NO_PROPAGATE_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT}, @@ -299,20 +397,28 @@ acl_match(acl_entry_t aclent, struct myacl_t *myacl) #endif { #if !HAVE_SUN_ACL +#if HAVE_DARWIN_ACL + void *q; + uid_t ugid; + int r, idtype; +#else gid_t g, *gp; uid_t u, *up; + acl_entry_type_t entry_type; +#endif /* !HAVE_DARWIN_ACL */ acl_tag_t tag_type; acl_permset_t opaque_ps; acl_flagset_t opaque_fs; - acl_entry_type_t entry_type; -#endif +#endif /* !HAVE_SUN_ACL */ int perms; #if HAVE_SUN_ACL perms = acl_permset_to_bitmap(ace->a_access_mask) | acl_flagset_to_bitmap(ace->a_flags); #else acl_get_tag_type(aclent, &tag_type); +#if !HAVE_DARWIN_ACL acl_get_entry_type_np(aclent, &entry_type); +#endif /* translate the silly opaque permset to a bitmap */ acl_get_permset(aclent, &opaque_ps); @@ -364,7 +470,43 @@ acl_match(acl_entry_t aclent, struct myacl_t *myacl) if ((uid_t)myacl->qual != ace->a_who) return (0); } -#else /* !HAVE_SUN_ACL */ +#elif HAVE_DARWIN_ACL + r = 0; + switch (tag_type) { + case ACL_EXTENDED_ALLOW: + if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_ALLOW) + return (0); + break; + case ACL_EXTENDED_DENY: + if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_DENY) + return (0); + break; + default: + return (0); + } + q = acl_get_qualifier(aclent); + if (q == NULL) + return (0); + r = mbr_uuid_to_id((const unsigned char *)q, &ugid, &idtype); + if (r != 0) + return (0); + switch (idtype) { + case ID_TYPE_UID: + if (myacl->tag != ARCHIVE_ENTRY_ACL_USER) + return (0); + if ((uid_t)myacl->qual != ugid) + return (0); + break; + case ID_TYPE_GID: + if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP) + return (0); + if ((gid_t)myacl->qual != ugid) + return (0); + break; + default: + return (0); + } +#else /* !HAVE_SUN_ACL && !HAVE_DARWIN_ACL */ switch (entry_type) { case ACL_ENTRY_TYPE_ALLOW: if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_ALLOW) @@ -416,7 +558,7 @@ acl_match(acl_entry_t aclent, struct myacl_t *myacl) if (myacl->tag != ARCHIVE_ENTRY_ACL_EVERYONE) return (0); break; } -#endif /* !HAVE_SUN_ACL */ +#endif /* !HAVE_SUN_ACL && !HAVE_DARWIN_ACL */ return (1); } @@ -456,6 +598,8 @@ compare_acls( */ #if HAVE_SUN_ACL for (e = 0; e < acl->acl_cnt; e++) +#elif HAVE_DARWIN_ACL + while (0 == acl_get_entry(acl, entry_id, &acl_entry)) #else while (1 == acl_get_entry(acl, entry_id, &acl_entry)) #endif @@ -554,7 +698,7 @@ compare_entry_acls(struct archive_entry *ae, struct myacl_t *myacls, const char } free(marker); } -#endif /* HAVE_SUN_ACL || (HAVE_POSIX_ACL && HAVE_ACL_TYPE_NFS4) */ +#endif /* HAVE_NFS4_ACL */ /* * Verify ACL restore-to-disk. This test is Platform-specific. @@ -562,7 +706,7 @@ compare_entry_acls(struct archive_entry *ae, struct myacl_t *myacls, const char DEFINE_TEST(test_acl_platform_nfs4) { -#if !HAVE_SUN_ACL && (!HAVE_POSIX_ACL || !HAVE_ACL_TYPE_NFS4) +#if !HAVE_NFS4_ACL skipping("NFS4 ACLs are not supported on this platform"); #else char buff[64]; @@ -571,21 +715,48 @@ DEFINE_TEST(test_acl_platform_nfs4) struct archive_entry *ae; int i, n; 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; +#else + const int regcnt = acls_reg_cnt; + const int dircnt = acls_dir_cnt; +#endif #if HAVE_SUN_ACL acl_t *acl; -#else +#else /* !HAVE_SUN_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 */ acl_t acl; -#endif +#endif /* !HAVE_SUN_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_SUN_ACL +#if HAVE_POSIX_ACL && HAVE_ACL_TYPE_NFS4 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. */ @@ -601,7 +772,11 @@ DEFINE_TEST(test_acl_platform_nfs4) n = acl_get("pretest", 0, &acl); #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 (n != 0) { @@ -640,7 +815,7 @@ DEFINE_TEST(test_acl_platform_nfs4) archive_entry_set_perm(ae, 0654); archive_entry_set_mtime(ae, 123456, 7890); archive_entry_set_size(ae, 0); - set_acls(ae, acls_reg, 0, (int)(sizeof(acls_reg)/sizeof(acls_reg[0]))); + set_acls(ae, acls_reg, 0, acls_reg_cnt); /* Write the entry to disk, including ACLs. */ assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae)); @@ -650,10 +825,10 @@ DEFINE_TEST(test_acl_platform_nfs4) archive_entry_set_filetype(ae, AE_IFDIR); archive_entry_set_perm(ae, 0654); archive_entry_set_mtime(ae, 123456, 7890); - set_acls(ae, acls_dir, 0, (int)(sizeof(acls_dir)/sizeof(acls_dir[0]))); + set_acls(ae, acls_dir, 0, acls_dir_cnt); assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae)); - for (i = 0; i < (int)(sizeof(acls_dir)/sizeof(acls_dir[0])); ++i) { + for (i = 0; i < acls_dir_cnt; ++i) { sprintf(buff, "dir%d", i); archive_entry_set_pathname(ae, buff); archive_entry_set_filetype(ae, AE_IFDIR); @@ -676,16 +851,20 @@ DEFINE_TEST(test_acl_platform_nfs4) n = acl_get("testall", 0, &acl); failure("acl_get(): errno = %d (%s)", errno, strerror(errno)); assertEqualInt(0, n); +#else +#if HAVE_DARWIN_ACL + acl = acl_get_file("testall", ACL_TYPE_EXTENDED); #else acl = acl_get_file("testall", ACL_TYPE_NFS4); +#endif failure("acl_get_file(): errno = %d (%s)", errno, strerror(errno)); assert(acl != (acl_t)NULL); #endif - compare_acls(acl, acls_reg, "testall", 0, (int)(sizeof(acls_reg)/sizeof(acls_reg[0]))); + compare_acls(acl, acls_reg, "testall", 0, regcnt); acl_free(acl); /* Verify single-permission dirs on disk. */ - for (i = 0; i < (int)(sizeof(acls_dir)/sizeof(acls_dir[0])); ++i) { + for (i = 0; i < dircnt; ++i) { sprintf(buff, "dir%d", i); assertEqualInt(0, stat(buff, &st)); assertEqualInt(st.st_mtime, 123456 + i); @@ -693,8 +872,12 @@ DEFINE_TEST(test_acl_platform_nfs4) n = acl_get(buff, 0, &acl); failure("acl_get(): errno = %d (%s)", errno, strerror(errno)); assertEqualInt(0, n); +#else +#if HAVE_DARWIN_ACL + acl = acl_get_file(buff, ACL_TYPE_EXTENDED); #else acl = acl_get_file(buff, ACL_TYPE_NFS4); +#endif failure("acl_get_file(): errno = %d (%s)", errno, strerror(errno)); assert(acl != (acl_t)NULL); @@ -710,13 +893,16 @@ DEFINE_TEST(test_acl_platform_nfs4) n = acl_get("dirall", 0, &acl); failure("acl_get(): errno = %d (%s)", errno, strerror(errno)); assertEqualInt(0, n); +#else +#if HAVE_DARWIN_ACL + acl = acl_get_file("dirall", ACL_TYPE_EXTENDED); #else acl = acl_get_file("dirall", ACL_TYPE_NFS4); +#endif failure("acl_get_file(): errno = %d (%s)", errno, strerror(errno)); assert(acl != (acl_t)NULL); #endif - compare_acls(acl, acls_dir, "dirall", 0, - (int)(sizeof(acls_dir)/sizeof(acls_dir[0]))); + compare_acls(acl, acls_dir, "dirall", 0, dircnt); acl_free(acl); /* Read and compare ACL via archive_read_disk */ @@ -727,8 +913,7 @@ DEFINE_TEST(test_acl_platform_nfs4) archive_entry_set_pathname(ae, "testall"); assertEqualInt(ARCHIVE_OK, archive_read_disk_entry_from_file(a, ae, -1, NULL)); - compare_entry_acls(ae, acls_reg, "testall", 0, - (int)(sizeof(acls_reg)/sizeof(acls_reg[0]))); + compare_entry_acls(ae, acls_reg, "testall", 0, acls_reg_cnt); archive_entry_free(ae); assertEqualInt(ARCHIVE_OK, archive_read_free(a)); @@ -740,9 +925,8 @@ DEFINE_TEST(test_acl_platform_nfs4) archive_entry_set_pathname(ae, "dirall"); assertEqualInt(ARCHIVE_OK, archive_read_disk_entry_from_file(a, ae, -1, NULL)); - compare_entry_acls(ae, acls_dir, "dirall", 0, - (int)(sizeof(acls_dir)/sizeof(acls_dir[0]))); + compare_entry_acls(ae, acls_dir, "dirall", 0, acls_dir_cnt); archive_entry_free(ae); assertEqualInt(ARCHIVE_OK, archive_read_free(a)); -#endif /* HAVE_SUN_ACL || (HAVE_POSIX_ACL && HAVE_ACL_TYPE_NFS4) */ +#endif /* HAVE_NFS4_ACL */ }