X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Ffile-has-acl.c;h=4ff2808a4a52a9c42216e49d80f9cc7cca19f60a;hb=2d540c2cb293bff09a2fe1b1bab9d1775d7e2832;hp=a815e4c47deb6f07b52be898b36cc5cf1e0f7e1e;hpb=d60f3b0c6b0f93a601acd1cfd3923f94ca05abb0;p=gnulib.git diff --git a/lib/file-has-acl.c b/lib/file-has-acl.c index a815e4c47..4ff2808a4 100644 --- a/lib/file-has-acl.c +++ b/lib/file-has-acl.c @@ -120,8 +120,6 @@ acl_access_nontrivial (acl_t acl) #elif USE_ACL && HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */ -# if !defined ACL_NO_TRIVIAL /* Solaris <= 10, Cygwin */ - /* Test an ACL retrieved with GETACL. Return 1 if the given ACL, consisting of COUNT entries, is non-trivial. Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */ @@ -148,7 +146,7 @@ acl_nontrivial (int count, aclent_t *entries) return 0; } -# ifdef ACE_GETACL +# ifdef ACE_GETACL /* Test an ACL retrieved with ACE_GETACL. Return 1 if the given ACL, consisting of COUNT entries, is non-trivial. @@ -167,7 +165,7 @@ acl_ace_nontrivial (int count, ace_t *entries) int old_convention = 0; for (i = 0; i < count; i++) - if (entries[i].a_flags & (ACE_OWNER | ACE_GROUP | ACE_OTHER)) + if (entries[i].a_flags & (OLD_ACE_OWNER | OLD_ACE_GROUP | OLD_ACE_OTHER)) { old_convention = 1; break; @@ -183,34 +181,123 @@ acl_ace_nontrivial (int count, ace_t *entries) If ace->a_flags = ACE_OWNER, ace->a_who is the st_uid from stat(). If ace->a_flags = ACE_GROUP, ace->a_who is the st_gid from stat(). We don't need to check ace->a_who in these cases. */ - if (!(ace->a_type == ALLOW - && (ace->a_flags == ACE_OWNER - || ace->a_flags == ACE_GROUP - || ace->a_flags == ACE_OTHER))) + if (!(ace->a_type == OLD_ALLOW + && (ace->a_flags == OLD_ACE_OWNER + || ace->a_flags == OLD_ACE_GROUP + || ace->a_flags == OLD_ACE_OTHER))) return 1; } else - /* Running on Solaris 10 (newer version) or Solaris 11. */ - for (i = 0; i < count; i++) - { - ace_t *ace = &entries[i]; + { + /* Running on Solaris 10 (newer version) or Solaris 11. */ + unsigned int access_masks[6] = + { + 0, /* owner@ deny */ + 0, /* owner@ allow */ + 0, /* group@ deny */ + 0, /* group@ allow */ + 0, /* everyone@ deny */ + 0 /* everyone@ allow */ + }; + + for (i = 0; i < count; i++) + { + ace_t *ace = &entries[i]; + unsigned int index1; + unsigned int index2; + + if (ace->a_type == NEW_ACE_ACCESS_ALLOWED_ACE_TYPE) + index1 = 1; + else if (ace->a_type == NEW_ACE_ACCESS_DENIED_ACE_TYPE) + index1 = 0; + else + return 1; - if (!(ace->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE - && (ace->a_flags == NEW_ACE_OWNER - || ace->a_flags - == (NEW_ACE_GROUP | NEW_ACE_IDENTIFIER_GROUP) - || ace->a_flags == ACE_EVERYONE) - && (ace->a_access_mask - & ~(NEW_ACE_READ_DATA | NEW_ACE_WRITE_DATA | NEW_ACE_EXECUTE)) - == 0)) - return 1; - } + if (ace->a_flags == NEW_ACE_OWNER) + index2 = 0; + else if (ace->a_flags == (NEW_ACE_GROUP | NEW_ACE_IDENTIFIER_GROUP)) + index2 = 2; + else if (ace->a_flags == NEW_ACE_EVERYONE) + index2 = 4; + else + return 1; + + access_masks[index1 + index2] |= ace->a_access_mask; + } + + /* The same bit shouldn't be both allowed and denied. */ + if (access_masks[0] & access_masks[1]) + return 1; + if (access_masks[2] & access_masks[3]) + return 1; + if (access_masks[4] & access_masks[5]) + return 1; + + /* Check minimum masks. */ + if ((NEW_ACE_WRITE_NAMED_ATTRS + | NEW_ACE_WRITE_ATTRIBUTES + | NEW_ACE_WRITE_ACL + | NEW_ACE_WRITE_OWNER) + & ~ access_masks[1]) + return 1; + access_masks[1] &= ~(NEW_ACE_WRITE_NAMED_ATTRS + | NEW_ACE_WRITE_ATTRIBUTES + | NEW_ACE_WRITE_ACL + | NEW_ACE_WRITE_OWNER); + if ((NEW_ACE_WRITE_NAMED_ATTRS + | NEW_ACE_WRITE_ATTRIBUTES + | NEW_ACE_WRITE_ACL + | NEW_ACE_WRITE_OWNER) + & ~ access_masks[4]) + return 1; + access_masks[4] &= ~(NEW_ACE_WRITE_NAMED_ATTRS + | NEW_ACE_WRITE_ATTRIBUTES + | NEW_ACE_WRITE_ACL + | NEW_ACE_WRITE_OWNER); + if ((NEW_ACE_READ_NAMED_ATTRS + | NEW_ACE_READ_ATTRIBUTES + | NEW_ACE_READ_ACL + | NEW_ACE_SYNCHRONIZE) + & ~ access_masks[5]) + return 1; + access_masks[5] &= ~(NEW_ACE_READ_NAMED_ATTRS + | NEW_ACE_READ_ATTRIBUTES + | NEW_ACE_READ_ACL + | NEW_ACE_SYNCHRONIZE); + + /* Check the allowed or denied bits. */ + if ((access_masks[0] | access_masks[1]) + != (NEW_ACE_READ_DATA + | NEW_ACE_WRITE_DATA | NEW_ACE_APPEND_DATA + | NEW_ACE_EXECUTE)) + return 1; + if ((access_masks[2] | access_masks[3]) + != (NEW_ACE_READ_DATA + | NEW_ACE_WRITE_DATA | NEW_ACE_APPEND_DATA + | NEW_ACE_EXECUTE)) + return 1; + if ((access_masks[4] | access_masks[5]) + != (NEW_ACE_READ_DATA + | NEW_ACE_WRITE_DATA | NEW_ACE_APPEND_DATA + | NEW_ACE_EXECUTE)) + return 1; + + /* Check that the NEW_ACE_WRITE_DATA and NEW_ACE_APPEND_DATA bits are + either both allowed or both denied. */ + if (((access_masks[0] & NEW_ACE_WRITE_DATA) != 0) + != ((access_masks[0] & NEW_ACE_APPEND_DATA) != 0)) + return 1; + if (((access_masks[2] & NEW_ACE_WRITE_DATA) != 0) + != ((access_masks[2] & NEW_ACE_APPEND_DATA) != 0)) + return 1; + if (((access_masks[4] & NEW_ACE_WRITE_DATA) != 0) + != ((access_masks[4] & NEW_ACE_APPEND_DATA) != 0)) + return 1; + } return 0; } -# endif - # endif #elif USE_ACL && HAVE_GETACL /* HP-UX */ @@ -234,6 +321,33 @@ acl_nontrivial (int count, struct acl_entry *entries, struct stat *sb) return 0; } +# if HAVE_ACLV_H /* HP-UX >= 11.11 */ + +/* Return 1 if the given ACL is non-trivial. + Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */ +int +aclv_nontrivial (int count, struct acl *entries) +{ + int i; + + for (i = 0; i < count; i++) + { + struct acl *ace = &entries[i]; + + /* Note: If ace->a_type = USER_OBJ, ace->a_id is the st_uid from stat(). + If ace->a_type = GROUP_OBJ, ace->a_id is the st_gid from stat(). + We don't need to check ace->a_id in these cases. */ + if (!(ace->a_type == USER_OBJ /* no need to check ace->a_id here */ + || ace->a_type == GROUP_OBJ /* no need to check ace->a_id here */ + || ace->a_type == CLASS_OBJ + || ace->a_type == OTHER_OBJ)) + return 1; + } + return 0; +} + +# endif + #elif USE_ACL && (HAVE_ACLX_GET || HAVE_STATACL) /* AIX */ /* Return 1 if the given ACL is non-trivial. @@ -325,7 +439,8 @@ acl_nontrivial (int count, struct acl *entries) /* Return 1 if NAME has a nontrivial access control list, 0 if NAME only has no or a base access control list, and -1 (setting errno) - on error. SB must be set to the stat buffer of FILE. */ + on error. SB must be set to the stat buffer of NAME, obtained + through stat() or lstat(). */ int file_has_acl (char const *name, struct stat const *sb) @@ -486,9 +601,15 @@ file_has_acl (char const *name, struct stat const *sb) if (count == 0) break; - /* If there are more than 3 entries, there cannot be only the - ACE_OWNER, ACE_GROUP, ACE_OTHER entries. */ - if (count > 3) + /* In the old (original Solaris 10) convention: + If there are more than 3 entries, there cannot be only the + ACE_OWNER, ACE_GROUP, ACE_OTHER entries. + In the newer Solaris 10 and Solaris 11 convention: + If there are more than 6 entries, there cannot be only the + ACE_OWNER, ACE_GROUP, ACE_EVERYONE entries, each once with + NEW_ACE_ACCESS_ALLOWED_ACE_TYPE and once with + NEW_ACE_ACCESS_DENIED_ACE_TYPE. */ + if (count > 6) return 1; entries = (ace_t *) malloc (count * sizeof (ace_t)); @@ -519,15 +640,23 @@ file_has_acl (char const *name, struct stat const *sb) # elif HAVE_GETACL /* HP-UX */ - int count; - struct acl_entry entries[NACLENTRIES]; - for (;;) { + int count; + struct acl_entry entries[NACLENTRIES]; + count = getacl (name, 0, NULL); if (count < 0) - return (errno == ENOSYS || errno == EOPNOTSUPP ? 0 : -1); + { + /* ENOSYS is seen on newer HP-UX versions. + EOPNOTSUPP is typically seen on NFS mounts. + ENOTSUP was seen on Quantum StorNext file systems (cvfs). */ + if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP) + break; + else + return -1; + } if (count == 0) return 0; @@ -555,6 +684,46 @@ file_has_acl (char const *name, struct stat const *sb) Repeat. */ } +# if HAVE_ACLV_H /* HP-UX >= 11.11 */ + + for (;;) + { + int count; + struct acl entries[NACLVENTRIES]; + + count = acl ((char *) name, ACL_CNT, NACLVENTRIES, entries); + + if (count < 0) + { + /* EOPNOTSUPP is seen on NFS in HP-UX 11.11, 11.23. + EINVAL is seen on NFS in HP-UX 11.31. */ + if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL) + break; + else + return -1; + } + + if (count == 0) + return 0; + + if (count > NACLVENTRIES) + /* If NACLVENTRIES cannot be trusted, use dynamic memory + allocation. */ + abort (); + + /* If there are more than 4 entries, there cannot be only the + four base ACL entries. */ + if (count > 4) + return 1; + + if (acl ((char *) name, ACL_GET, count, entries) == count) + return aclv_nontrivial (count, entries); + /* Huh? The number of ACL entries changed since the last call. + Repeat. */ + } + +# endif + # elif HAVE_ACLX_GET && defined ACL_AIX_WIP /* AIX */ acl_type_t type; @@ -570,6 +739,8 @@ file_has_acl (char const *name, struct stat const *sb) type.u64 = ACL_ANY; if (aclx_get (name, 0, &type, aclbuf, &aclsize, &mode) >= 0) break; + if (errno == ENOSYS) + return 0; if (errno != ENOSPC) { if (acl != aclbuf) @@ -634,7 +805,12 @@ file_has_acl (char const *name, struct stat const *sb) count = acl ((char *) name, ACL_CNT, NACLENTRIES, NULL); if (count < 0) - return -1; + { + if (errno == ENOSYS || errno == ENOTSUP) + break; + else + return -1; + } if (count == 0) return 0;