changeset 15570:cd0bdf15a524

acl: Improve support of NFSv4 ACLs on Solaris 10 (newer version). * lib/acl-internal.h (acl_nontrivial): Declare also on newer Solaris 10. * lib/file-has-acl.c (acl_nontrivial): Define also on newer Solaris 10. (acl_ace_nontrivial): Likewise. Recognize the trivial ACLs with 6 ACEs. * lib/copy-acl.c (qcopy_acl): On newer Solaris 10, use acl or facl instead of acl_get, facl_get, acl_set, facl_set.
author Bruno Haible <bruno@clisp.org>
date Mon, 05 Sep 2011 23:45:11 +0200
parents bc7d656f8f54
children 5d1d1c0b8204
files ChangeLog lib/acl-internal.h lib/copy-acl.c lib/file-has-acl.c
diffstat 4 files changed, 123 insertions(+), 22 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2011-09-05  Bruno Haible  <bruno@clisp.org>
+
+	acl: Improve support of NFSv4 ACLs on Solaris 10 (newer version).
+	* lib/acl-internal.h (acl_nontrivial): Declare also on newer Solaris
+	10.
+	* lib/file-has-acl.c (acl_nontrivial): Define also on newer Solaris 10.
+	(acl_ace_nontrivial): Likewise. Recognize the trivial ACLs with 6 ACEs.
+	* lib/copy-acl.c (qcopy_acl): On newer Solaris 10, use acl or facl
+	instead of acl_get, facl_get, acl_set, facl_set.
+
 2011-09-05  Bruno Haible  <bruno@clisp.org>
 
 	copy-file: Try unit tests on more file systems.
--- a/lib/acl-internal.h
+++ b/lib/acl-internal.h
@@ -183,7 +183,7 @@
 #   define MODE_INSIDE_ACL 1
 #  endif
 
-#  if !defined ACL_NO_TRIVIAL /* Solaris <= 10, Cygwin */
+#  if !(defined ACL_NO_TRIVIAL && 0) /* Solaris <= 10, Cygwin */
 
 /* Return 1 if the given ACL is non-trivial.
    Return 0 if it is trivial, i.e. equivalent to a simple stat() mode.  */
--- a/lib/copy-acl.c
+++ b/lib/copy-acl.c
@@ -181,7 +181,7 @@
 
 #elif USE_ACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
 
-# if defined ACL_NO_TRIVIAL
+# if defined ACL_NO_TRIVIAL && 0
   /* Solaris 10 (newer version), which has additional API declared in
      <sys/acl.h> (acl_t) and implemented in libsec (acl_set, acl_trivial,
      acl_fromtext, ...).  */
--- a/lib/file-has-acl.c
+++ b/lib/file-has-acl.c
@@ -120,7 +120,7 @@
 
 #elif USE_ACL && HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
 
-# if !defined ACL_NO_TRIVIAL /* Solaris <= 10, Cygwin */
+# if !(defined ACL_NO_TRIVIAL && 0) /* Solaris <= 10, Cygwin */
 
 /* Test an ACL retrieved with GETACL.
    Return 1 if the given ACL, consisting of COUNT entries, is non-trivial.
@@ -167,7 +167,7 @@
   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,28 +183,119 @@
            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_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 == 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;
 
-        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;
-      }
+      /* 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;
 }