From 7c2e36888a6f0d63557fc2b98a8c8f3d3cb73aa3 Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Sun, 3 Oct 2010 18:03:48 +0200 Subject: [PATCH] acl: Add support for ACLs on NonStop Kernel. * m4/acl.m4 (gl_FUNC_ACL): For Solaris, test for facl(), not for acl(). Check whether the function aclsort() exists. * lib/acl-internal.h: For Solaris, test HAVE_FACL, not HAVE_ACL. (acl_nontrivial) [HAVE_ACLSORT]: New declaration. * lib/file-has-acl.c: For Solaris, test HAVE_FACL, not HAVE_ACL. (acl_nontrivial [HAVE_ACLSORT]: New function. (file_has_acl): Implement for NonStop Kernel. * lib/set-mode-acl.c: For Solaris, test HAVE_FACL, not HAVE_ACL. (qset_acl): Implement for NonStop Kernel. * lib/copy-acl.c (qcopy_acl): Implement for NonStop Kernel. * tests/test-sameacls.c: For Solaris, test HAVE_FACL, not HAVE_ACL. (main): Implement for NonStop Kernel. * tests/test-file-has-acl.sh (acl_flavor): Set to 'nsk' on NonStop Kernel. Handle this flavor. * tests/test-set-mode-acl.sh: Likewise. * tests/test-copy-acl.sh: Likewise. * tests/test-copy-file.sh: Likewise. --- ChangeLog | 22 +++++++++++++++ lib/acl-internal.h | 10 +++++-- lib/copy-acl.c | 62 +++++++++++++++++++++++++++++++++++++++++ lib/file-has-acl.c | 61 ++++++++++++++++++++++++++++++++++++++-- lib/set-mode-acl.c | 47 ++++++++++++++++++++++++++++++- m4/acl.m4 | 16 ++++++++--- tests/test-copy-acl.sh | 56 +++++++++++++++++++++++++++++++++++-- tests/test-copy-file.sh | 56 +++++++++++++++++++++++++++++++++++-- tests/test-file-has-acl.sh | 24 ++++++++++++++-- tests/test-sameacls.c | 69 ++++++++++++++++++++++++++++++++++++++++++++-- tests/test-set-mode-acl.sh | 13 +++++++-- 11 files changed, 415 insertions(+), 21 deletions(-) diff --git a/ChangeLog b/ChangeLog index 74db2aea8..18d7d4b59 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,26 @@ 2010-10-03 Bruno Haible + Joachim Schmitz (tiny change) + + acl: Add support for ACLs on NonStop Kernel. + * m4/acl.m4 (gl_FUNC_ACL): For Solaris, test for facl(), not for acl(). + Check whether the function aclsort() exists. + * lib/acl-internal.h: For Solaris, test HAVE_FACL, not HAVE_ACL. + (acl_nontrivial) [HAVE_ACLSORT]: New declaration. + * lib/file-has-acl.c: For Solaris, test HAVE_FACL, not HAVE_ACL. + (acl_nontrivial [HAVE_ACLSORT]: New function. + (file_has_acl): Implement for NonStop Kernel. + * lib/set-mode-acl.c: For Solaris, test HAVE_FACL, not HAVE_ACL. + (qset_acl): Implement for NonStop Kernel. + * lib/copy-acl.c (qcopy_acl): Implement for NonStop Kernel. + * tests/test-sameacls.c: For Solaris, test HAVE_FACL, not HAVE_ACL. + (main): Implement for NonStop Kernel. + * tests/test-file-has-acl.sh (acl_flavor): Set to 'nsk' on NonStop + Kernel. Handle this flavor. + * tests/test-set-mode-acl.sh: Likewise. + * tests/test-copy-acl.sh: Likewise. + * tests/test-copy-file.sh: Likewise. + +2010-10-03 Bruno Haible Info about ACLs on NonStop Kernel. * doc/acl-resources.txt: Add info about NonStop Kernel. diff --git a/lib/acl-internal.h b/lib/acl-internal.h index 7f9cde16d..33a76e3e2 100644 --- a/lib/acl-internal.h +++ b/lib/acl-internal.h @@ -26,7 +26,7 @@ #if HAVE_SYS_ACL_H # include #endif -#if defined HAVE_ACL && ! defined GETACLCNT && defined ACL_CNT +#if defined HAVE_FACL && ! defined GETACLCNT && defined ACL_CNT # define GETACLCNT ACL_CNT #endif @@ -158,7 +158,7 @@ extern int acl_extended_nontrivial (acl_t); extern int acl_access_nontrivial (acl_t); # endif -# elif HAVE_ACL && defined GETACL /* Solaris, Cygwin, not HP-UX */ +# elif HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */ /* Set to 1 if a file's mode is implicit by the ACL. Set to 0 if a file's mode is stored independently from the ACL. */ @@ -216,6 +216,12 @@ extern int acl_nontrivial (int count, struct acl_entry *entries, struct stat *sb Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */ extern int acl_nontrivial (struct acl *a); +# elif HAVE_ACLSORT /* NonStop Kernel */ + +/* Return 1 if the given ACL is non-trivial. + Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */ +extern int acl_nontrivial (int count, struct acl *entries); + # endif #endif diff --git a/lib/copy-acl.c b/lib/copy-acl.c index 421907de9..e8a4460f5 100644 --- a/lib/copy-acl.c +++ b/lib/copy-acl.c @@ -516,6 +516,68 @@ qcopy_acl (const char *src_name, int source_desc, const char *dst_name, return 0; +#elif USE_ACL && HAVE_ACLSORT /* NonStop Kernel */ + + int count; + struct acl entries[NACLENTRIES]; + int ret; + + for (;;) + { + count = acl ((char *) src_name, ACL_CNT, NACLENTRIES, NULL); + + if (count < 0) + { + if (0) + { + count = 0; + break; + } + else + return -2; + } + + if (count == 0) + break; + + if (count > NACLENTRIES) + /* If NACLENTRIES cannot be trusted, use dynamic memory allocation. */ + abort (); + + if (acl ((char *) src_name, ACL_GET, count, entries) == count) + break; + /* Huh? The number of ACL entries changed since the last call. + Repeat. */ + } + + if (count == 0) + return qset_acl (dst_name, dest_desc, mode); + + ret = acl ((char *) dst_name, ACL_SET, count, entries); + if (ret < 0) + { + int saved_errno = errno; + + if (0) + { + if (!acl_nontrivial (count, entries)) + return chmod_or_fchmod (dst_name, dest_desc, mode); + } + + chmod_or_fchmod (dst_name, dest_desc, mode); + errno = saved_errno; + return -1; + } + + if (mode & (S_ISUID | S_ISGID | S_ISVTX)) + { + /* We did not call chmod so far, and either the mode and the ACL are + separate or special bits are to be set which don't fit into ACLs. */ + + return chmod_or_fchmod (dst_name, dest_desc, mode); + } + return 0; + #else return qset_acl (dst_name, dest_desc, mode); diff --git a/lib/file-has-acl.c b/lib/file-has-acl.c index 92aa07ed0..c11c63aeb 100644 --- a/lib/file-has-acl.c +++ b/lib/file-has-acl.c @@ -118,7 +118,7 @@ acl_access_nontrivial (acl_t acl) # endif -#elif USE_ACL && HAVE_ACL && defined GETACL /* Solaris, Cygwin, not HP-UX */ +#elif USE_ACL && HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */ # if !defined ACL_NO_TRIVIAL /* Solaris <= 10, Cygwin */ @@ -294,6 +294,32 @@ acl_nfs4_nontrivial (nfs4_acl_int_t *a) # endif +#elif USE_ACL && HAVE_ACLSORT /* NonStop Kernel */ + +/* Test an ACL retrieved with ACL_GET. + 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. */ +int +acl_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 @@ -377,7 +403,7 @@ file_has_acl (char const *name, struct stat const *sb) return ACL_NOT_WELL_SUPPORTED (errno) ? 0 : -1; return ret; -# elif HAVE_ACL && defined GETACLCNT /* Solaris, Cygwin, not HP-UX */ +# elif HAVE_FACL && defined GETACLCNT /* Solaris, Cygwin, not HP-UX */ # if defined ACL_NO_TRIVIAL @@ -598,6 +624,37 @@ file_has_acl (char const *name, struct stat const *sb) return acl_nontrivial (&u.a); +# elif HAVE_ACLSORT /* NonStop Kernel */ + + int count; + struct acl entries[NACLENTRIES]; + + for (;;) + { + count = acl ((char *) name, ACL_CNT, NACLENTRIES, NULL); + + if (count < 0) + return -1; + + if (count == 0) + return 0; + + if (count > NACLENTRIES) + /* If NACLENTRIES 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 acl_nontrivial (count, entries); + /* Huh? The number of ACL entries changed since the last call. + Repeat. */ + } + # endif } #endif diff --git a/lib/set-mode-acl.c b/lib/set-mode-acl.c index 2cd2c75f3..f24ed0f27 100644 --- a/lib/set-mode-acl.c +++ b/lib/set-mode-acl.c @@ -201,7 +201,7 @@ qset_acl (char const *name, int desc, mode_t mode) return chmod_or_fchmod (name, desc, mode); # endif -# elif HAVE_ACL && defined GETACLCNT /* Solaris, Cygwin, not HP-UX */ +# elif HAVE_FACL && defined GETACLCNT /* Solaris, Cygwin, not HP-UX */ # if defined ACL_NO_TRIVIAL /* Solaris 10 (newer version), which has additional API declared in @@ -573,6 +573,51 @@ qset_acl (char const *name, int desc, mode_t mode) return ret; +# elif HAVE_ACLSORT /* NonStop Kernel */ + + struct acl entries[4]; + int ret; + + entries[0].a_type = USER_OBJ; + entries[0].a_id = 0; /* irrelevant */ + entries[0].a_perm = (mode >> 6) & 7; + entries[1].a_type = GROUP_OBJ; + entries[1].a_id = 0; /* irrelevant */ + entries[1].a_perm = (mode >> 3) & 7; + entries[2].a_type = CLASS_OBJ; + entries[2].a_id = 0; + entries[2].a_perm = (mode >> 3) & 7; + entries[3].a_type = OTHER_OBJ; + entries[3].a_id = 0; + entries[3].a_perm = mode & 7; + + ret = aclsort (sizeof (entries) / sizeof (struct acl), 1, entries); + if (ret > 0) + abort (); + if (ret < 0) + { + if (0) + return chmod_or_fchmod (name, desc, mode); + return -1; + } + + ret = acl ((char *) name, ACL_SET, + sizeof (entries) / sizeof (struct acl), entries); + if (ret < 0) + { + if (0) + return chmod_or_fchmod (name, desc, mode); + return -1; + } + + if (mode & (S_ISUID | S_ISGID | S_ISVTX)) + { + /* We did not call chmod so far, so the special bits have not yet + been set. */ + return chmod_or_fchmod (name, desc, mode); + } + return 0; + # else /* Unknown flavor of ACLs */ return chmod_or_fchmod (name, desc, mode); # endif diff --git a/m4/acl.m4 b/m4/acl.m4 index 6033d06e4..dd047a32e 100644 --- a/m4/acl.m4 +++ b/m4/acl.m4 @@ -1,5 +1,5 @@ # acl.m4 - check for access control list (ACL) primitives -# serial 10 +# serial 11 # Copyright (C) 2002, 2004-2010 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation @@ -76,8 +76,8 @@ int type = ACL_TYPE_EXTENDED;]])], dnl Test for Solaris API (Solaris, Cygwin). if test $use_acl = 0; then - AC_CHECK_FUNCS([acl]) - if test $ac_cv_func_acl = yes; then + AC_CHECK_FUNCS([facl]) + if test $ac_cv_func_facl = yes; then AC_SEARCH_LIBS([acl_trivial], [sec], [if test "$ac_cv_search_acl_trivial" != "none required"; then LIB_ACL=$ac_cv_search_acl_trivial @@ -89,7 +89,7 @@ int type = ACL_TYPE_EXTENDED;]])], fi dnl Test for HP-UX API. - if test $use_acl = 0 || test "$ac_cv_func_acl" = yes; then + if test $use_acl = 0; then AC_CHECK_FUNCS([getacl]) if test $ac_cv_func_getacl = yes; then use_acl=1 @@ -112,6 +112,14 @@ int type = ACL_TYPE_EXTENDED;]])], fi fi + dnl Test for NonStop Kernel API. + if test $use_acl = 0; then + AC_CHECK_FUNCS([aclsort]) + if test $ac_cv_func_aclsort = yes; then + use_acl=1 + fi + fi + LIBS=$ac_save_LIBS fi if test "x$enable_acl$use_acl" = "xyes0"; then diff --git a/tests/test-copy-acl.sh b/tests/test-copy-acl.sh index a16990b21..1452c8085 100755 --- a/tests/test-copy-acl.sh +++ b/tests/test-copy-acl.sh @@ -91,8 +91,14 @@ cd "$builddir" || acl_flavor=hpux else if (getacl tmpfile0 >/dev/null) 2>/dev/null; then - # Tru64. - acl_flavor=osf1 + # Tru64, NonStop Kernel. + if (getacl -m tmpfile0 >/dev/null) 2>/dev/null; then + # Tru64. + acl_flavor=osf1 + else + # NonStop Kernel. + acl_flavor=nsk + fi else if (aclget tmpfile0 >/dev/null) 2>/dev/null; then # AIX. @@ -132,7 +138,7 @@ cd "$builddir" || cmp tmpaclout1 tmpaclout2 > /dev/null } ;; - osf1) + osf1 | nsk) func_test_same_acls () { getacl "$1" | sed -e "s/$1/FILENAME/g" > tmpaclout1 @@ -411,6 +417,50 @@ cd "$builddir" || ;; + nsk) + + # Set an ACL for a user. + setacl -m user:$auid:1 tmpfile0 + + func_test_copy tmpfile0 tmpfile2 + + # Set an ACL for a group. + setacl -m group:$agid:4 tmpfile0 + + func_test_copy tmpfile0 tmpfile3 + + # Set an ACL for other. + setacl -m other:4 tmpfile0 + + func_test_copy tmpfile0 tmpfile4 + + # Remove the ACL for the user. + setacl -d user:$auid tmpfile0 + + func_test_copy tmpfile0 tmpfile5 + + # Remove the ACL for the group. + setacl -d group:$agid tmpfile0 + + func_test_copy tmpfile0 tmpfile6 + + # Delete all optional ACLs. + setacl -m user:$auid:1 tmpfile0 + setacl -s user::6,group::0,class:7,other:0 tmpfile0 + + func_test_copy tmpfile0 tmpfile8 + + # Copy ACLs from a file that has no ACLs. + echo > tmpfile9 + chmod a+x tmpfile9 + getacl tmpfile9 > tmpaclout0 + setacl -f tmpaclout0 tmpfile0 + rm -f tmpfile9 + + func_test_copy tmpfile0 tmpfile9 + + ;; + aix) # Set an ACL for a user. diff --git a/tests/test-copy-file.sh b/tests/test-copy-file.sh index bf71b3b13..c63f380dd 100755 --- a/tests/test-copy-file.sh +++ b/tests/test-copy-file.sh @@ -85,8 +85,14 @@ cd "$builddir" || acl_flavor=hpux else if (getacl tmpfile0 >/dev/null) 2>/dev/null; then - # Tru64. - acl_flavor=osf1 + # Tru64, NonStop Kernel. + if (getacl -m tmpfile0 >/dev/null) 2>/dev/null; then + # Tru64. + acl_flavor=osf1 + else + # NonStop Kernel. + acl_flavor=nsk + fi else if (aclget tmpfile0 >/dev/null) 2>/dev/null; then # AIX. @@ -126,7 +132,7 @@ cd "$builddir" || cmp tmpaclout1 tmpaclout2 > /dev/null } ;; - osf1) + osf1 | nsk) func_test_same_acls () { getacl "$1" | sed -e "s/$1/FILENAME/g" > tmpaclout1 @@ -405,6 +411,50 @@ cd "$builddir" || ;; + nsk) + + # Set an ACL for a user. + setacl -m user:$auid:1 tmpfile0 + + func_test_copy tmpfile0 tmpfile2 + + # Set an ACL for a group. + setacl -m group:$agid:4 tmpfile0 + + func_test_copy tmpfile0 tmpfile3 + + # Set an ACL for other. + setacl -m other:4 tmpfile0 + + func_test_copy tmpfile0 tmpfile4 + + # Remove the ACL for the user. + setacl -d user:$auid tmpfile0 + + func_test_copy tmpfile0 tmpfile5 + + # Remove the ACL for the group. + setacl -d group:$agid tmpfile0 + + func_test_copy tmpfile0 tmpfile6 + + # Delete all optional ACLs. + setacl -m user:$auid:1 tmpfile0 + setacl -s user::6,group::0,class:7,other:0 tmpfile0 + + func_test_copy tmpfile0 tmpfile8 + + # Copy ACLs from a file that has no ACLs. + echo > tmpfile9 + chmod a+x tmpfile9 + getacl tmpfile9 > tmpaclout0 + setacl -f tmpaclout0 tmpfile0 + rm -f tmpfile9 + + func_test_copy tmpfile0 tmpfile9 + + ;; + aix) # Set an ACL for a user. diff --git a/tests/test-file-has-acl.sh b/tests/test-file-has-acl.sh index db6738870..3f49e8d9e 100755 --- a/tests/test-file-has-acl.sh +++ b/tests/test-file-has-acl.sh @@ -91,8 +91,14 @@ cd "$builddir" || acl_flavor=hpux else if (getacl tmpfile0 >/dev/null) 2>/dev/null; then - # Tru64. - acl_flavor=osf1 + # Tru64, NonStop Kernel. + if (getacl -m tmpfile0 >/dev/null) 2>/dev/null; then + # Tru64. + acl_flavor=osf1 + else + # NonStop Kernel. + acl_flavor=nsk + fi else if (aclget tmpfile0 >/dev/null) 2>/dev/null; then # AIX. @@ -286,6 +292,20 @@ cd "$builddir" || fi ;; + nsk) + + # Set an ACL for a user. + setacl -m user:$auid:1 tmpfile0 + + func_test_has_acl tmpfile0 yes + + # Remove the ACL for the user. + setacl -d user:$auid tmpfile0 + + func_test_has_acl tmpfile0 no + + ;; + aix) # Set an ACL for a user. diff --git a/tests/test-sameacls.c b/tests/test-sameacls.c index 7dcec2ae5..6bd4f5e8b 100644 --- a/tests/test-sameacls.c +++ b/tests/test-sameacls.c @@ -24,7 +24,7 @@ #include #include -#if HAVE_ACL_GET_FILE || HAVE_ACL || HAVE_ACLX_GET || HAVE_STATACL +#if HAVE_ACL_GET_FILE || HAVE_FACL || HAVE_ACLX_GET || HAVE_STATACL || HAVE_ACLSORT # include # include #endif @@ -218,7 +218,7 @@ main (int argc, char *argv[]) } } } -#elif HAVE_ACL && defined GETACL /* Solaris, Cygwin, not HP-UX */ +#elif HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */ int count1; int count2; @@ -520,6 +520,71 @@ main (int argc, char *argv[]) file1, file2); return 1; } +#elif HAVE_ACLSORT /* NonStop Kernel */ + int count1; + int count2; + + count1 = acl ((char *) file1, ACL_CNT, NACLENTRIES, NULL); + count2 = acl ((char *) file2, ACL_CNT, NACLENTRIES, NULL); + + if (count1 < 0) + { + fprintf (stderr, "error accessing the ACLs of file %s\n", file1); + fflush (stderr); + abort (); + } + if (count2 < 0) + { + fprintf (stderr, "error accessing the ACLs of file %s\n", file2); + fflush (stderr); + abort (); + } + if (count1 != count2) + { + fprintf (stderr, "files %s and %s have different number of ACLs: %d and %d\n", + file1, file2, count1, count2); + return 1; + } + else if (count1 > 0) + { + struct acl *entries1 = XNMALLOC (count1, struct acl); + struct acl *entries2 = XNMALLOC (count2, struct acl); + int i; + + if (acl ((char *) file1, ACL_GET, count1, entries1) < count1) + { + fprintf (stderr, "error retrieving the ACLs of file %s\n", file1); + fflush (stderr); + abort (); + } + if (acl ((char *) file2, ACL_GET, count2, entries2) < count1) + { + fprintf (stderr, "error retrieving the ACLs of file %s\n", file2); + fflush (stderr); + abort (); + } + for (i = 0; i < count1; i++) + { + if (entries1[i].a_type != entries2[i].a_type) + { + fprintf (stderr, "files %s and %s: different ACL entry #%d: different types %d and %d\n", + file1, file2, i, entries1[i].a_type, entries2[i].a_type); + return 1; + } + if (entries1[i].a_id != entries2[i].a_id) + { + fprintf (stderr, "files %s and %s: different ACL entry #%d: different ids %d and %d\n", + file1, file2, i, (int)entries1[i].a_id, (int)entries2[i].a_id); + return 1; + } + if (entries1[i].a_perm != entries2[i].a_perm) + { + fprintf (stderr, "files %s and %s: different ACL entry #%d: different permissions %03o and %03o\n", + file1, file2, i, (unsigned int) entries1[i].a_perm, (unsigned int) entries2[i].a_perm); + return 1; + } + } + } #endif } diff --git a/tests/test-set-mode-acl.sh b/tests/test-set-mode-acl.sh index ef2b71607..56fde29e5 100755 --- a/tests/test-set-mode-acl.sh +++ b/tests/test-set-mode-acl.sh @@ -91,8 +91,14 @@ cd "$builddir" || acl_flavor=hpux else if (getacl tmpfile0 >/dev/null) 2>/dev/null; then - # Tru64. - acl_flavor=osf1 + # Tru64, NonStop Kernel. + if (getacl -m tmpfile0 >/dev/null) 2>/dev/null; then + # Tru64. + acl_flavor=osf1 + else + # NonStop Kernel. + acl_flavor=nsk + fi else if (aclget tmpfile0 >/dev/null) 2>/dev/null; then # AIX. @@ -175,6 +181,9 @@ cd "$builddir" || osf1) setacl -u user:$auid:1 tmpfile0 ;; + nsk) + setacl -m user:$auid:1 tmpfile0 + ;; aix) { aclget tmpfile0 | sed -e 's/disabled$/enabled/'; echo " permit --x u:$auid"; } | aclput tmpfile0 ;; -- 2.11.0