X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Ffile-has-acl.c;h=89a63a658c6d3b0108e0638fedb775817b443a8a;hb=5eb934dfd78a8ff086ffef87f5d4ec18e2d45cf7;hp=3d4d5c16ff0a27807903962edc40e6670918715d;hpb=227b08bbf68b66e8d7cd4da5c1a6f0ebf5a5d9e8;p=gnulib.git diff --git a/lib/file-has-acl.c b/lib/file-has-acl.c index 3d4d5c16f..89a63a658 100644 --- a/lib/file-has-acl.c +++ b/lib/file-has-acl.c @@ -1,6 +1,6 @@ /* Test whether a file has a nontrivial access control list. - Copyright (C) 2002-2003, 2005-2011 Free Software Foundation, Inc. + Copyright (C) 2002-2003, 2005-2012 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,6 +17,12 @@ Written by Paul Eggert, Andreas Grünbacher, and Bruno Haible. */ +/* Without this pragma, gcc 4.7.0 20120126 may suggest that the + file_has_acl function might be candidate for attribute 'const' */ +#if (__GNUC__ == 4 && 6 <= __GNUC_MINOR__) || 4 < __GNUC__ +# pragma GCC diagnostic ignored "-Wsuggest-attribute=const" +#endif + #include #include "acl.h" @@ -120,8 +126,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 +152,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 +171,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 +187,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 */ @@ -352,7 +445,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) @@ -513,9 +607,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)); @@ -645,6 +745,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) @@ -709,7 +811,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;