/* Test whether a file has a nontrivial access control list.
- Copyright (C) 2002-2003, 2005-2008 Free Software Foundation, Inc.
+ Copyright (C) 2002-2003, 2005-2009 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
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
- Written by Paul Eggert and Andreas Gruenbacher. */
+ Written by Paul Eggert, Andreas Grünbacher, and Bruno Haible. */
#include <config.h>
# if HAVE_ACL_FIRST_ENTRY /* Linux, FreeBSD */
acl_entry_t ace;
- int at_end;
+ int got_one;
- for (at_end = acl_get_entry (acl, ACL_FIRST_ENTRY, &ace);
- !at_end;
- at_end = acl_get_entry (acl, ACL_NEXT_ENTRY, &ace))
+ for (got_one = acl_get_entry (acl, ACL_FIRST_ENTRY, &ace);
+ got_one > 0;
+ got_one = acl_get_entry (acl, ACL_NEXT_ENTRY, &ace))
{
acl_tag_t tag;
if (acl_get_tag_type (ace, &tag) < 0)
if (!(tag == ACL_USER_OBJ || tag == ACL_GROUP_OBJ || tag == ACL_OTHER))
return 1;
}
- return 0;
+ return got_one;
# else /* IRIX, Tru64 */
# if HAVE_ACL_TO_SHORT_TEXT /* IRIX */
#elif USE_ACL && HAVE_ACL && 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. */
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.
{
int i;
+ /* The flags in the ace_t structure changed in a binary incompatible way
+ when ACL_NO_TRIVIAL etc. were introduced in <sys/acl.h> version 1.15.
+ How to distinguish the two conventions at runtime?
+ In the old convention, usually three ACEs have a_flags = ACE_OWNER /
+ ACE_GROUP / ACE_OTHER, in the range 0x0100..0x0400. In the new
+ convention, these values are not used. */
+ int old_convention = 0;
+
for (i = 0; i < count; i++)
- {
- ace_t *ace = &entries[i];
-
- /* Note: 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)))
- return 1;
- }
+ if (entries[i].a_flags & (ACE_OWNER | ACE_GROUP | ACE_OTHER))
+ {
+ old_convention = 1;
+ break;
+ }
+
+ if (old_convention)
+ /* Running on Solaris 10. */
+ for (i = 0; i < count; i++)
+ {
+ ace_t *ace = &entries[i];
+
+ /* Note:
+ 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)))
+ return 1;
+ }
+ else
+ /* Running on Solaris 10 (newer version) or Solaris 11. */
+ for (i = 0; i < count; i++)
+ {
+ ace_t *ace = &entries[i];
+
+ 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;
+ }
+
return 0;
}
+# endif
+
# endif
#elif USE_ACL && HAVE_GETACL /* HP-UX */
return 0;
}
+#elif USE_ACL && HAVE_ACLX_GET && 0 /* AIX */
+
+/* TODO */
+
+#elif USE_ACL && HAVE_STATACL /* older AIX */
+
+/* Return 1 if the given ACL is non-trivial.
+ Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */
+int
+acl_nontrivial (struct acl *a)
+{
+ /* The normal way to iterate through an ACL is like this:
+ struct acl_entry *ace;
+ for (ace = a->acl_ext; ace != acl_last (a); ace = acl_nxt (ace))
+ {
+ struct ace_id *aei;
+ switch (ace->ace_type)
+ {
+ case ACC_PERMIT:
+ case ACC_DENY:
+ case ACC_SPECIFY:
+ ...;
+ }
+ for (aei = ace->ace_id; aei != id_last (ace); aei = id_nxt (aei))
+ ...
+ }
+ */
+ return (acl_last (a) != a->acl_ext ? 1 : 0);
+}
+
#endif
# elif HAVE_ACL && defined GETACLCNT /* Solaris, Cygwin, not HP-UX */
-# if HAVE_ACL_TRIVIAL
+# if defined ACL_NO_TRIVIAL
/* Solaris 10 (newer version), which has additional API declared in
<sys/acl.h> (acl_t) and implemented in libsec (acl_set, acl_trivial,
Repeat. */
}
+# elif HAVE_ACLX_GET && 0 /* AIX */
+
+ /* TODO: use aclx_get(), and then? */
+
+# elif HAVE_STATACL /* older AIX */
+
+ union { struct acl a; char room[4096]; } u;
+
+ if (statacl (name, STX_NORMAL, &u.a, sizeof (u)) < 0)
+ return -1;
+
+ return acl_nontrivial (&u.a);
+
# endif
}
#endif
- /* FIXME: Add support for AIX. Please see Samba's
- source/lib/sysacls.c file for fix-related ideas. */
-
return 0;
}