From ab7e231a8239c3d85e0ac0c97513a6100effabd2 Mon Sep 17 00:00:00 2001 From: David Bartley Date: Sat, 9 May 2009 03:23:19 -0400 Subject: [PATCH] Add support for returning access control list text. --- ChangeLog | 11 +++ lib/acl.h | 10 ++- lib/file-has-acl.c | 156 +++++++++++++++++++++++++++++++++++++++++---- lib/free-acl-text.c | 46 +++++++++++++ m4/acl.m4 | 2 +- modules/acl | 3 +- tests/test-file-has-acl.c | 3 +- 7 files changed, 213 insertions(+), 18 deletions(-) create mode 100644 lib/free-acl-text.c diff --git a/ChangeLog b/ChangeLog index 2f2055d..be88e39 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2009-05-09 David Bartley + + Add support for returning access control list text + * lib/file-has-acl.c: Add additional parameters for returning access + and default access control lists. + * lib/free-acl-text.c: Add free_acl_text function. + * lib/acl.h: Add free_acl_text function and file_has_acl flags. + * m4/acl.m4: Check for acl_to_any_text. + * modules/acl: Add free-acl-text.c + * tests/test-file-has-acl.c: Update per changes to file_has_acl. + 2009-05-08 Bruno Haible * lib/sys_socket.in.h (_SS_PADSIZE): Use a conditional expression diff --git a/lib/acl.h b/lib/acl.h index fcb00f5..3fdb3bc 100644 --- a/lib/acl.h +++ b/lib/acl.h @@ -1,6 +1,6 @@ /* acl.c - access control lists - Copyright (C) 2002, 2008 Free Software Foundation, Inc. + Copyright (C) 2002, 2008, 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 @@ -20,7 +20,13 @@ #include #include -int file_has_acl (char const *, struct stat const *); +/* Flags for file_has_acl. */ +#define GL_ACL_SHORT_FORMAT 0x01 +#define GL_ACL_NUMERIC_IDS 0x02 +#define GL_ACL_PRINT_INDENTS 0x04 + +int file_has_acl (char const *, struct stat const *, int, char **, char**); +void free_acl_text (char *); int copy_acl (char const *, int, char const *, int, mode_t); int set_acl (char const *, int, mode_t); int qset_acl (char const *, int, mode_t); diff --git a/lib/file-has-acl.c b/lib/file-has-acl.c index c3b77c3..e3505ca 100644 --- a/lib/file-has-acl.c +++ b/lib/file-has-acl.c @@ -15,7 +15,8 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . - Written by Paul Eggert, Andreas Grünbacher, and Bruno Haible. */ + Written by Paul Eggert, Andreas Grünbacher, Bruno Haible, and + David Bartley. */ #include @@ -120,6 +121,17 @@ acl_access_nontrivial (acl_t acl) #elif USE_ACL && HAVE_ACL && defined GETACL /* Solaris, Cygwin, not HP-UX */ +static void +replace_chr (char *str, char c1, char c2) +{ + while (*str) + { + if (*str == c1) + *str = c2; + str++; + } +} + # if !defined ACL_NO_TRIVIAL /* Solaris <= 10, Cygwin */ /* Test an ACL retrieved with GETACL. @@ -269,12 +281,22 @@ acl_nontrivial (struct acl *a) /* 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 FILE. If ATEXT and + DTEXT are non-null they will be filled with a text representation + of the access and default (if applicable) access control list if + it is nontrivial. FLAGS contains formatting flags for ATEXT and + DTEXT. atext and dtext should be free'd by calling free_acl_text. */ int -file_has_acl (char const *name, struct stat const *sb) +file_has_acl (char const *name, struct stat const *sb, int flags, + char **atext, char **dtext) { #if USE_ACL + if (dtext) + *dtext = NULL; + if (atext) + *atext = NULL; + if (! S_ISLNK (sb->st_mode)) { # if HAVE_ACL_GET_FILE @@ -283,14 +305,14 @@ file_has_acl (char const *name, struct stat const *sb) /* Linux, FreeBSD, MacOS X, IRIX, Tru64 */ int ret; - if (HAVE_ACL_EXTENDED_FILE) /* Linux */ + if (! atext && ! dtext && HAVE_ACL_EXTENDED_FILE) /* Linux */ { /* On Linux, acl_extended_file is an optimized function: It only makes two calls to getxattr(), one for ACL_TYPE_ACCESS, one for ACL_TYPE_DEFAULT. */ ret = acl_extended_file (name); } - else /* FreeBSD, MacOS X, IRIX, Tru64 */ + else /* Linux, FreeBSD, MacOS X, IRIX, Tru64 */ { # if HAVE_ACL_TYPE_EXTENDED /* MacOS X */ /* On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS) @@ -302,17 +324,47 @@ file_has_acl (char const *name, struct stat const *sb) if (acl) { ret = acl_extended_nontrivial (acl); + if (ret && atext) + { + *atext = acl_to_text (acl, &len); + if (! *atext) + ret = -1; + } acl_free (acl); } else ret = -1; -# else /* FreeBSD, IRIX, Tru64 */ +# else /* Linux, FreeBSD, IRIX, Tru64 */ acl_t acl = acl_get_file (name, ACL_TYPE_ACCESS); if (acl) { int saved_errno; + ssize_t len; ret = acl_access_nontrivial (acl); + if (ret && atext) + { +# if HAVE_ACL_TO_SHORT_TEXT /* IRIX */ + if (flags & GL_ACL_SHORT_FORMAT) + *atext = acl_to_short_text (acl, &len); + else + *atext = acl_to_text (acl, &len); +# elif HAVE_ACL_TO_ANY_TEXT /* Linux */ + int flags2 = TEXT_SOME_EFFECTIVE; + if (flags & GL_ACL_SHORT_FORMAT) + flags2 |= TEXT_ABBREVIATE; + if (flags & GL_ACL_NUMERIC_IDS) + flags2 |= TEXT_NUMERIC_IDS; + if (flags & GL_ACL_PRINT_INDENTS) + flags2 |= TEXT_SMART_INDENT; + *atext = acl_to_any_text (acl, "", '\n', flags2); +# else /* FreeBSD, Tru64 */ + + *atext = acl_to_text (acl, &len); +# endif + if (! *atext) + ret = -1; + } saved_errno = errno; acl_free (acl); errno = saved_errno; @@ -320,19 +372,47 @@ file_has_acl (char const *name, struct stat const *sb) /* On OSF/1, acl_get_file (name, ACL_TYPE_DEFAULT) always returns NULL with errno not set. There is no point in making this call. */ -# else /* FreeBSD, IRIX */ +# else /* Linux, FreeBSD, IRIX */ /* On Linux, FreeBSD, IRIX, acl_get_file (name, ACL_TYPE_ACCESS) and acl_get_file (name, ACL_TYPE_DEFAULT) on a directory either both succeed or both fail; it depends on the filesystem. Therefore there is no point in making the second - call if the first one already failed. */ - if (ret == 0 && S_ISDIR (sb->st_mode)) + call if the first one already failed. If the access acl is + non-trivial and dtext is null we don't need to continue. */ + if ((ret == 0 || (ret == 1 && dtext)) && S_ISDIR (sb->st_mode)) { acl = acl_get_file (name, ACL_TYPE_DEFAULT); if (acl) { - ret = (0 < acl_entries (acl)); + if (acl_entries (acl) > 0) + { + ret = 1; + if (dtext) + { +# if HAVE_ACL_TO_SHORT_TEXT /* IRIX */ + if (! (flags & GL_ACL_SHORT_FORMAT)) + *dtext = acl_to_short_text (acl, &len); + else + *dtext = acl_to_text (acl, &len); +# elif HAVE_ACL_TO_ANY_TEXT /* Linux */ + int flags2 = TEXT_SOME_EFFECTIVE; + if (flags & GL_ACL_SHORT_FORMAT) + flags2 |= TEXT_ABBREVIATE; + if (flags & GL_ACL_NUMERIC_IDS) + flags2 |= TEXT_NUMERIC_IDS; + if (flags & GL_ACL_PRINT_INDENTS) + flags2 |= TEXT_SMART_INDENT; + *dtext = acl_to_any_text (acl, "", '\n', flags2); +# else /* FreeBSD */ + *dtext = acl_to_text (acl, &len); +# endif + if (! *dtext) + ret = -1; + } + } + saved_errno = errno; acl_free (acl); + errno = saved_errno; } else ret = -1; @@ -344,7 +424,22 @@ file_has_acl (char const *name, struct stat const *sb) # endif } if (ret < 0) - return ACL_NOT_WELL_SUPPORTED (errno) ? 0 : -1; + { + if (atext) + { + free_acl_text (*atext); + *atext = NULL; + } +/* Linux, FreeBSD, IRIX */ +# if HAVE_ACL_GET_FILE && ! HAVE_ACL_TYPE_EXTENDED && ! HAVE_ACL_FREE_TEXT + if (dtext) + { + free_acl_text (*dtext); + *dtext = NULL; + } +# endif + return ACL_NOT_WELL_SUPPORTED (errno) ? 0 : -1; + } return ret; # elif HAVE_ACL && defined GETACLCNT /* Solaris, Cygwin, not HP-UX */ @@ -354,7 +449,32 @@ file_has_acl (char const *name, struct stat const *sb) /* Solaris 10 (newer version), which has additional API declared in (acl_t) and implemented in libsec (acl_set, acl_trivial, acl_fromtext, ...). */ - return acl_trivial (name); + if (atext) + { + int ret; + acl_t *aclp; + + ret = acl_get (name, ACL_NO_TRIVIAL, &aclp); + if (ret == 0) + { + if (aclp) + { + int flags2 = 0; + if (flags & GL_ACL_SHORT_FORMAT) + flags2 |= ACL_COMPACT_FMT; + *atext = acl_totext (aclp, flags2); + if (*atext) + replace_chr (*atext, ',', '\n'); + else + ret = -1; + acl_free (aclp); + } + else + ret = 0; + } + } + else + return acl_trivial (name); # else /* Solaris, Cygwin, general case */ @@ -384,7 +504,7 @@ file_has_acl (char const *name, struct stat const *sb) returns only 3 entries for files with no ACL. But this is safe: If there are more than 4 entries, there cannot be only the "user::", "group::", "other:", and "mask:" entries. */ - if (count > 4) + if (! atext && count > 4) return 1; entries = (aclent_t *) malloc (count * sizeof (aclent_t)); @@ -397,6 +517,16 @@ file_has_acl (char const *name, struct stat const *sb) { if (acl_nontrivial (count, entries)) { + if (atext) + { + *atext = acltotext (entries, count); + if (! *atext) + { + free (entries); + return -1; + } + replace_chr (*atext, ',', '\n'); + } free (entries); return 1; } diff --git a/lib/free-acl-text.c b/lib/free-acl-text.c new file mode 100644 index 0000000..230808d --- /dev/null +++ b/lib/free-acl-text.c @@ -0,0 +1,46 @@ +/* Free text allocated by file_has_acl. + + Copyright (C) 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 + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Written by David Bartley. */ + +#include + +#include + +#include "acl.h" + +#include "acl-internal.h" + + +/* Free text allocated by file_has_acl. */ + +void +free_acl_text (char *text) +{ +#if USE_ACL + if (text) + { +# if HAVE_ACL_FREE_TEXT /* Tru64 */ + acl_free_text (text); +# elif HAVE_ACL_FREE /* Linux, FreeBSD, MacOS X, IRIX */ + acl_free (text); +# else /* Solaris */ + free (text); +# endif + } +#endif +} diff --git a/m4/acl.m4 b/m4/acl.m4 index 5340e2e..ce7ff85 100644 --- a/m4/acl.m4 +++ b/m4/acl.m4 @@ -36,7 +36,7 @@ AC_DEFUN([gl_FUNC_ACL], acl_delete_def_file acl_extended_file \ acl_delete_fd_np acl_delete_file_np \ acl_copy_ext_native acl_create_entry_np \ - acl_to_short_text acl_free_text]) + acl_to_short_text acl_to_any_text acl_free_text]) # If the acl_get_file bug is detected, don't enable the ACL support. gl_ACL_GET_FILE([use_acl=1], []) if test $use_acl = 1; then diff --git a/modules/acl b/modules/acl index 2185242..2e57b0b 100644 --- a/modules/acl +++ b/modules/acl @@ -8,6 +8,7 @@ lib/acl_entries.c lib/set-mode-acl.c lib/copy-acl.c lib/file-has-acl.c +lib/free-acl-text.c m4/acl.m4 Depends-on: @@ -20,7 +21,7 @@ configure.ac: gl_FUNC_ACL Makefile.am: -lib_SOURCES += set-mode-acl.c copy-acl.c file-has-acl.c +lib_SOURCES += set-mode-acl.c copy-acl.c file-has-acl.c free-acl-text.c Include: "acl.h" diff --git a/tests/test-file-has-acl.c b/tests/test-file-has-acl.c index 5685f41..e1ace65 100644 --- a/tests/test-file-has-acl.c +++ b/tests/test-file-has-acl.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -65,7 +66,7 @@ main (int argc, char *argv[]) #if USE_ACL { - int ret = file_has_acl (file, &statbuf); + int ret = file_has_acl (file, &statbuf, 0, NULL, NULL); if (ret < 0) { fprintf (stderr, "could not access the ACL of file \"%s\"\n", file); -- 1.5.6.5