From 49f595839f2f60ddcf622bc59bbd57b8cd42870e Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Sun, 27 Sep 2009 14:05:56 +0200 Subject: [PATCH] Add support for new flavours of ACLs on AIX. (Untested.) --- ChangeLog | 9 ++++ lib/file-has-acl.c | 100 ++++++++++++++++++++++++++++++++++++--- lib/set-mode-acl.c | 106 +++++++++++++++++++++++++++++++++++++++++- tests/test-sameacls.c | 8 +++- 4 files changed, 212 insertions(+), 11 deletions(-) diff --git a/ChangeLog b/ChangeLog index f1bcf697bb..7f713d804f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2008-12-07 Bruno Haible + + Add support for new flavours of ACLs on AIX. (Untested.) + * lib/file-has-acl.c [AIX] (acl_nfs4_nontrivial): New function. + (file_has_acl): Add support for newer AIX. + * lib/set-mode-acl.c (qset_acl): Likewise. + * tests/test-sameacls.c (main): Fix use of aclx_get function. Hint by + Rainer Tammer . + 2009-09-26 Eric Blake argp: fix compilation of getopt diff --git a/lib/file-has-acl.c b/lib/file-has-acl.c index c3b77c395f..4ad57107c6 100644 --- a/lib/file-has-acl.c +++ b/lib/file-has-acl.c @@ -234,11 +234,7 @@ acl_nontrivial (int count, struct acl_entry *entries, struct stat *sb) return 0; } -#elif USE_ACL && HAVE_ACLX_GET && 0 /* AIX */ - -/* TODO */ - -#elif USE_ACL && HAVE_STATACL /* older AIX */ +#elif USE_ACL && (HAVE_ACLX_GET || HAVE_STATACL) /* AIX */ /* Return 1 if the given ACL is non-trivial. Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */ @@ -264,6 +260,40 @@ acl_nontrivial (struct acl *a) return (acl_last (a) != a->acl_ext ? 1 : 0); } +# if HAVE_ACLX_GET /* newer 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_nfs4_nontrivial (nfs4_acl_int_t *a) +{ +# if 1 /* let's try this first */ + return (a->aclEntryN > 0 ? 1 : 0); +# else + int count = a->aclEntryN; + int i; + + for (i = 0; i < count; i++) + { + nfs4_ace_int_t *ace = &a->aclEntry[i]; + + if (!((ace->flags & ACE4_ID_SPECIAL) != 0 + && (ace->aceWho.special_whoid == ACE4_WHO_OWNER + || ace->aceWho.special_whoid == ACE4_WHO_GROUP + || ace->aceWho.special_whoid == ACE4_WHO_EVERYONE) + && ace->aceType == ACE4_ACCESS_ALLOWED_ACE_TYPE + && ace->aceFlags == 0 + && (ace->aceMask & ~(ACE4_READ_DATA | ACE4_LIST_DIRECTORY + | ACE4_WRITE_DATA | ACE4_ADD_FILE + | ACE4_EXECUTE)) == 0)) + return 1; + } + return 0; +# endif +} + +# endif + #endif @@ -499,9 +529,65 @@ file_has_acl (char const *name, struct stat const *sb) Repeat. */ } -# elif HAVE_ACLX_GET && 0 /* AIX */ +# elif HAVE_ACLX_GET /* AIX */ + + acl_type_t type; + char aclbuf[1024]; + void *acl = aclbuf; + size_t aclsize = sizeof (aclbuf); + mode_t mode; + + for (;;) + { + /* The docs say that type being 0 is equivalent to ACL_ANY, but it + is not true, in AIX 5.3. */ + type.u64 = ACL_ANY; + if (aclx_get (name, 0, &type, aclbuf, &aclsize, &mode) >= 0) + break; + if (errno != ENOSPC) + { + if (acl != aclbuf) + { + int saved_errno = errno; + free (acl); + errno = saved_errno; + } + return -1; + } + aclsize = 2 * aclsize; + if (acl != aclbuf) + free (acl); + acl = malloc (aclsize); + if (acl == NULL) + { + errno = ENOMEM; + return -1; + } + } - /* TODO: use aclx_get(), and then? */ + if (type.u64 == ACL_AIXC) + { + int result = acl_nontrivial ((struct acl *) acl); + if (acl != aclbuf) + free (acl); + return result; + } + else if (type.u64 == ACL_NFS4) + { + int result = acl_nfs4_nontrivial ((nfs4_acl_int_t *) acl); + if (acl != aclbuf) + free (acl); + return result; + } + else + { + /* A newer type of ACL has been introduced in the system. + We should better support it. */ + if (acl != aclbuf) + free (acl); + errno = EINVAL; + return -1; + } # elif HAVE_STATACL /* older AIX */ diff --git a/lib/set-mode-acl.c b/lib/set-mode-acl.c index 34076db202..c3747a6ed7 100644 --- a/lib/set-mode-acl.c +++ b/lib/set-mode-acl.c @@ -445,10 +445,112 @@ qset_acl (char const *name, int desc, mode_t mode) } return 0; -# elif HAVE_ACLX_GET && 0 /* AIX */ +# elif HAVE_ACLX_GET /* AIX */ - /* TODO: use aclx_fput or aclx_put, respectively */ + acl_type_list_t types; + size_t types_size = sizeof (types); + acl_type_t type; + if (aclx_gettypes (name, &types, &types_size) < 0 + || types.num_entries == 0) + return chmod_or_fchmod (name, desc, mode); + + /* XXX Do we need to clear all types of ACLs for the given file, or is it + sufficient to clear the first one? */ + type = types.entries[0]; + if (type.u64 == ACL_AIXC) + { + union { struct acl a; char room[128]; } u; + int ret; + + u.a.acl_len = (char *) &u.a.acl_ext[0] - (char *) &u.a; /* no entries */ + u.a.acl_mode = mode & ~(S_IXACL | 0777); + u.a.u_access = (mode >> 6) & 7; + u.a.g_access = (mode >> 3) & 7; + u.a.o_access = mode & 7; + + if (desc != -1) + ret = aclx_fput (desc, SET_ACL | SET_MODE_S_BITS, + type, &u.a, u.a.acl_len, mode); + else + ret = aclx_put (name, SET_ACL | SET_MODE_S_BITS, + type, &u.a, u.a.acl_len, mode); + if (!(ret < 0 && errno == ENOSYS)) + return ret; + } + else if (type.u64 == ACL_NFS4) + { + union { nfs4_acl_int_t a; char room[128]; } u; + nfs4_ace_int_t *ace; + int ret; + + u.a.aclVersion = NFS4_ACL_INT_STRUCT_VERSION; + u.a.aclEntryN = 0; + ace = &u.a.aclEntry[0]; + { + ace->flags = ACE4_ID_SPECIAL; + ace->aceWho.special_whoid = ACE4_WHO_OWNER; + ace->aceType = ACE4_ACCESS_ALLOWED_ACE_TYPE; + ace->aceFlags = 0; + ace->aceMask = + (mode & 0400 ? ACE4_READ_DATA | ACE4_LIST_DIRECTORY : 0) + | (mode & 0200 + ? ACE4_WRITE_DATA | ACE4_ADD_FILE | ACE4_APPEND_DATA + | ACE4_ADD_SUBDIRECTORY + : 0) + | (mode & 0100 ? ACE4_EXECUTE : 0); + ace->aceWhoString[0] = '\0'; + ace->entryLen = (char *) &ace->aceWhoString[4] - (char *) ace; + ace = (nfs4_ace_int_t *) (char *) &ace->aceWhoString[4]; + u.a.aclEntryN++; + } + { + ace->flags = ACE4_ID_SPECIAL; + ace->aceWho.special_whoid = ACE4_WHO_GROUP; + ace->aceType = ACE4_ACCESS_ALLOWED_ACE_TYPE; + ace->aceFlags = 0; + ace->aceMask = + (mode & 0040 ? ACE4_READ_DATA | ACE4_LIST_DIRECTORY : 0) + | (mode & 0020 + ? ACE4_WRITE_DATA | ACE4_ADD_FILE | ACE4_APPEND_DATA + | ACE4_ADD_SUBDIRECTORY + : 0) + | (mode & 0010 ? ACE4_EXECUTE : 0); + ace->aceWhoString[0] = '\0'; + ace->entryLen = (char *) &ace->aceWhoString[4] - (char *) ace; + ace = (nfs4_ace_int_t *) (char *) &ace->aceWhoString[4]; + u.a.aclEntryN++; + } + { + ace->flags = ACE4_ID_SPECIAL; + ace->aceWho.special_whoid = ACE4_WHO_EVERYONE; + ace->aceType = ACE4_ACCESS_ALLOWED_ACE_TYPE; + ace->aceFlags = 0; + ace->aceMask = + (mode & 0004 ? ACE4_READ_DATA | ACE4_LIST_DIRECTORY : 0) + | (mode & 0002 + ? ACE4_WRITE_DATA | ACE4_ADD_FILE | ACE4_APPEND_DATA + | ACE4_ADD_SUBDIRECTORY + : 0) + | (mode & 0001 ? ACE4_EXECUTE : 0); + ace->aceWhoString[0] = '\0'; + ace->entryLen = (char *) &ace->aceWhoString[4] - (char *) ace; + ace = (nfs4_ace_int_t *) (char *) &ace->aceWhoString[4]; + u.a.aclEntryN++; + } + u.a.aclLength = (char *) ace - (char *) &u.a; + + if (desc != -1) + ret = aclx_fput (desc, SET_ACL | SET_MODE_S_BITS, + type, &u.a, u.a.aclLength, mode); + else + ret = aclx_put (name, SET_ACL | SET_MODE_S_BITS, + type, &u.a, u.a.aclLength, mode); + if (!(ret < 0 && errno == ENOSYS)) + return ret; + } + + return chmod_or_fchmod (name, desc, mode); # elif HAVE_STATACL /* older AIX */ union { struct acl a; char room[128]; } u; diff --git a/tests/test-sameacls.c b/tests/test-sameacls.c index 20b0a4742d..736be57bf0 100644 --- a/tests/test-sameacls.c +++ b/tests/test-sameacls.c @@ -447,7 +447,9 @@ main (int argc, char *argv[]) mode_t mode2; char text2[1000]; - memset (&type1, 0, sizeof (type1)); /* type1 = ACL_ANY */ + /* The docs say that type1 being 0 is equivalent to ACL_ANY, but it is not + true, in AIX 5.3. */ + type1.u64 = ACL_ANY; if (aclx_get (file1, 0, &type1, acl1, &aclsize1, &mode1) < 0) { fprintf (stderr, "error accessing the ACLs of file %s\n", file1); @@ -461,7 +463,9 @@ main (int argc, char *argv[]) abort (); } - memset (&type2, 0, sizeof (type2)); /* type2 = ACL_ANY */ + /* The docs say that type1 being 0 is equivalent to ACL_ANY, but it is not + true, in AIX 5.3. */ + type2.u64 = ACL_ANY; if (aclx_get (file2, 0, &type2, acl2, &aclsize2, &mode2) < 0) { fprintf (stderr, "error accessing the ACLs of file %s\n", file2); -- 2.30.2