This is for GNU coreutils, whose ‘ls’ can be made faster with the new function because it means (for example) that ‘ls’ needn’t call both listxattr and lgetxattr in the common case where the file has no extended attributes. * lib/acl.h (ACL_SYMLINK_FOLLOW): New constant. (struct aclinfo): New type. * lib/file-has-acl.c (UNKNOWN_SECURITY_CONTEXT): New constant. (USE_LINUX_XATTR): New macro. When set: Include stdint.h (for uint32_t). If also USE_SELINUX_SELINUX_H, include selinux/selinux.h (for getfilecon). If HAVE_SMACK, include <sys/smack.h>, otherwise provide substitutes for smack_smackfs_path and smack_new_label_from_path. (is_smack_enabled): New function. (aclinfo_has_xattr): Rename from have_xattr and make it extern. Use struct aclinfo const * arg instead of char const * and ssize_t. Work even if ai->size < 0. Supply a no-op macro on platforms lacking xattr. (get_aclinfo): New static function, much of it taken from coreutils/src/ls.c. (file_has_aclinfo): New function, which generalizes file_has_acl to provide more info. Its body is taken from the old file_has_acl with new stuff from ls.c. (file_has_acl): Use it. (aclinfo_scontext_free, aclinfo_free): Nwew functions, if not already no-op macros. * m4/acl.m4 (gl_FUNC_ACL_ARG): Add --without-libsmack option. (gl_FILE_HAS_ACL): Check for libsmack, selinux. * m4/selinux-selinux-h.m4 (gl_CHECK_HEADER_SELINUX_SELINUX_H): New macro, for use by file-has-acl. Rename HAVE_SELINUX_SELINUX_H to USE_SELINUX_SELINUX_H to avoid confusion as to whether we have <selinux/selinux.h>; all uses changed. (gl_HEADERS_SELINUX_SELINUX_H): Use the new macro. * modules/file-has-acl (Files): Add m4/selinux-selinux-h.m4. (Depends-on): Add errno, ssize_t. * tests/test-file-has-acl.c (main): Add a little test for file_has_aclinfo. --- ChangeLog | 40 +++++ lib/acl.h | 53 +++++++ lib/file-has-acl.c | 310 ++++++++++++++++++++++++++++---------- lib/se-selinux.in.h | 2 +- m4/acl.m4 | 39 ++++- m4/selinux-selinux-h.m4 | 34 +++-- modules/file-has-acl | 3 + modules/selinux-h | 2 +- tests/test-file-has-acl.c | 11 ++ 9 files changed, 398 insertions(+), 96 deletions(-)
diff --git a/ChangeLog b/ChangeLog index 071f0f0fc7..3368abacb4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,43 @@ +2024-09-29 Paul Eggert <egg...@cs.ucla.edu> + + file-has-acl: new function file_has_aclinfo + This is for GNU coreutils, whose ‘ls’ can be made faster with the + new function because it means (for example) that ‘ls’ needn’t call + both listxattr and lgetxattr in the common case where the file has + no extended attributes. + * lib/acl.h (ACL_SYMLINK_FOLLOW): New constant. + (struct aclinfo): New type. + * lib/file-has-acl.c (UNKNOWN_SECURITY_CONTEXT): New constant. + (USE_LINUX_XATTR): New macro. When set: + Include stdint.h (for uint32_t). If also USE_SELINUX_SELINUX_H, + include selinux/selinux.h (for getfilecon). + If HAVE_SMACK, include <sys/smack.h>, otherwise provide substitutes + for smack_smackfs_path and smack_new_label_from_path. + (is_smack_enabled): New function. + (aclinfo_has_xattr): Rename from have_xattr and make it extern. + Use struct aclinfo const * arg instead of char const * and ssize_t. + Work even if ai->size < 0. Supply a no-op macro on platforms + lacking xattr. + (get_aclinfo): New static function, much of it taken from + coreutils/src/ls.c. + (file_has_aclinfo): New function, which generalizes file_has_acl + to provide more info. Its body is taken from the old file_has_acl + with new stuff from ls.c. + (file_has_acl): Use it. + (aclinfo_scontext_free, aclinfo_free): Nwew functions, if not + already no-op macros. + * m4/acl.m4 (gl_FUNC_ACL_ARG): Add --without-libsmack option. + (gl_FILE_HAS_ACL): Check for libsmack, selinux. + * m4/selinux-selinux-h.m4 (gl_CHECK_HEADER_SELINUX_SELINUX_H): + New macro, for use by file-has-acl. Rename HAVE_SELINUX_SELINUX_H + to USE_SELINUX_SELINUX_H to avoid confusion as to whether we have + <selinux/selinux.h>; all uses changed. + (gl_HEADERS_SELINUX_SELINUX_H): Use the new macro. + * modules/file-has-acl (Files): Add m4/selinux-selinux-h.m4. + (Depends-on): Add errno, ssize_t. + * tests/test-file-has-acl.c (main): Add a little test for + file_has_aclinfo. + 2024-09-26 Bruno Haible <br...@clisp.org> string-buffer tests: Avoid test failure on native Windows. diff --git a/lib/acl.h b/lib/acl.h index 475231c2db..07ab04250d 100644 --- a/lib/acl.h +++ b/lib/acl.h @@ -32,9 +32,62 @@ extern "C" { #endif +/* Follow symlinks when getting an ACL. */ +enum { ACL_SYMLINK_FOLLOW = 1 }; + +/* Information about an ACL. */ +struct aclinfo +{ + /* If 'size' is nonnegative, a buffer holding the concatenation + of extended attribute names, each terminated by NUL + (either u.__gl_acl_ch, or heap-allocated). */ + char *buf; + + /* The number of useful bytes at the start of buf, counting trailing NULs. + If negative, there was an error in getting the ACL info, + and u.err is the corresponding errno. */ + ssize_t size; + + /* The allocated size of buf. This is sizeof u.__gl_acl_ch if the + buffer is not heap-allocated, and is larger otherwise. + For internal use only. */ + ssize_t __gl_acl_alloc; + + /* Security context string. Do not modify its contents. */ + char *scontext; + /* Security context errno value. It is zero if there was no + error getting the security context. When nonzero, scontext is "?". */ + int scontext_err; + + union + { + /* An errno value, when there was an error getting the ACL info. */ + int err; + + /* A small array of char, big enough for most listxattr results. + The size is somewhat arbitrary. For internal use only. */ + char __gl_acl_ch[152]; + } u; +}; bool acl_errno_valid (int) _GL_ATTRIBUTE_CONST; int file_has_acl (char const *, struct stat const *); +int file_has_aclinfo (char const *, struct stat const *, struct aclinfo *, int); + +#if USE_ACL && HAVE_LINUX_XATTR_H && HAVE_LISTXATTR +bool aclinfo_has_xattr (struct aclinfo const *, char const *) + _GL_ATTRIBUTE_PURE; +void aclinfo_free (struct aclinfo *); +#else +# define aclinfo_has_xattr(ai, xattr) false +# define aclinfo_free(ai) ((void) 0) +#endif +#if (USE_ACL && HAVE_LINUX_XATTR_H && HAVE_LISTXATTR \ + && (HAVE_SMACK || USE_SELINUX_SELINUX_H)) +void aclinfo_scontext_free (char *); +#else +# define aclinfo_scontext_free(s) ((void) 0) +#endif int qset_acl (char const *, int, mode_t); int xset_acl (char const *, int, mode_t); diff --git a/lib/file-has-acl.c b/lib/file-has-acl.c index 06759a4948..89faba565f 100644 --- a/lib/file-has-acl.c +++ b/lib/file-has-acl.c @@ -31,8 +31,16 @@ #include "attribute.h" #include "minmax.h" -#if USE_ACL && HAVE_LINUX_XATTR_H && HAVE_LISTXATTR +static char const UNKNOWN_SECURITY_CONTEXT[] = "?"; + +#define USE_LINUX_XATTR (USE_ACL && HAVE_LINUX_XATTR_H && HAVE_LISTXATTR) + +#if USE_LINUX_XATTR +# if USE_SELINUX_SELINUX_H +# include <selinux/selinux.h> +# endif # include <stdckdint.h> +# include <stdint.h> # include <string.h> # include <arpa/inet.h> # include <sys/xattr.h> @@ -47,26 +55,185 @@ # define XATTR_NAME_POSIX_ACL_DEFAULT "system.posix_acl_default" # endif +# ifdef HAVE_SMACK +# include <sys/smack.h> +# else +static char const * +smack_smackfs_path (void) +{ + return NULL; +} +static ssize_t +smack_new_label_from_path (MAYBE_UNUSED const char *path, + MAYBE_UNUSED const char *xattr, + MAYBE_UNUSED int follow, MAYBE_UNUSED char **label) +{ + return -1; +} +# endif +static bool +is_smack_enabled (void) +{ + return !!smack_smackfs_path (); +} + enum { /* ACE4_ACCESS_ALLOWED_ACE_TYPE = 0x00000000, */ ACE4_ACCESS_DENIED_ACE_TYPE = 0x00000001, ACE4_IDENTIFIER_GROUP = 0x00000040 }; -/* Return true if ATTR is in the set represented by the NUL-terminated - strings in LISTBUF, which is of size LISTSIZE. */ +/* Does AI's xattr set contain XATTR? */ -ATTRIBUTE_PURE static bool -have_xattr (char const *attr, char const *listbuf, ssize_t listsize) +bool +aclinfo_has_xattr (struct aclinfo const *ai, char const *xattr) { - char const *blim = listbuf + listsize; - for (char const *b = listbuf; b < blim; b += strlen (b) + 1) - for (char const *a = attr; *a == *b; a++, b++) - if (!*a) - return true; + if (0 < ai->size) + { + char const *blim = ai->buf + ai->size; + for (char const *b = ai->buf; b < blim; b += strlen (b) + 1) + for (char const *a = xattr; *a == *b; a++, b++) + if (!*a) + return true; + } return false; } +/* Get attributes of the file NAME into AI. + If FLAGS & ACL_SYMLINK_FOLLOW, follow symbolic links. */ +static void +get_aclinfo (char const *name, struct aclinfo *ai, int flags) +{ + int scontext_err = ENOTSUP; + ai->buf = ai->u.__gl_acl_ch; + ai->__gl_acl_alloc = sizeof ai->u.__gl_acl_ch; + + ssize_t (*lsxattr) (char const *, char *, size_t) + = (flags & ACL_SYMLINK_FOLLOW ? listxattr : llistxattr); + while (true) + { + ai->size = lsxattr (name, ai->buf, ai->__gl_acl_alloc); + if (0 < ai->size) + break; + ai->u.err = ai->size < 0 ? errno : 0; + if (! (ai->size < 0 && ai->u.err == ERANGE)) + break; + + /* The buffer was too small. Find how large it should have been. */ + ssize_t size = lsxattr (name, NULL, 0); + if (size <= 0) + { + ai->size = size; + ai->u.err = size < 0 ? errno : 0; + break; + } + + /* Grow allocation to at least 'size'. Grow it by a nontrivial + amount, to defend against denial of service by an adversary + that fiddles with ACLs. */ + ssize_t larger_alloc; + if (ckd_add (&larger_alloc, ai->__gl_acl_alloc, ai->__gl_acl_alloc >> 1)) + { + ai->u.err = ENOMEM; + break; + } + if (ai->buf != ai->u.__gl_acl_ch) + { + free (ai->buf); + ai->buf = ai->u.__gl_acl_ch; + ai->__gl_acl_alloc = sizeof ai->u.__gl_acl_ch; + } + ssize_t newalloc = MAX (size, larger_alloc); + if (SIZE_MAX < newalloc) + { + ai->u.err = ENOMEM; + break; + } + char *newbuf = malloc (newalloc); + if (!newbuf) + { + ai->u.err = errno; + break; + } + ai->buf = newbuf; + ai->__gl_acl_alloc = newalloc; + } + + if (0 < ai->size) + { + if (is_smack_enabled ()) + { + if (aclinfo_has_xattr (ai, XATTR_NAME_SMACK)) + { + ssize_t r = smack_new_label_from_path (name, "security.SMACK64", + flags & ACL_SYMLINK_FOLLOW, + &ai->scontext); + scontext_err = r < 0 ? errno : 0; + } + } + else + { +# if USE_SELINUX_SELINUX_H + if (aclinfo_has_xattr (ai, XATTR_NAME_SELINUX)) + { + ssize_t r = + ((flags & ACL_SYMLINK_FOLLOW ? getfilecon : lgetfilecon) + (name, &ai->scontext)); + scontext_err = r < 0 ? errno : 0; +# ifndef SE_SELINUX_INLINE + /* Gnulib's selinux-h module is not in use, so getfilecon and + lgetfilecon can misbehave, be it via an old version of + libselinux where these would return 0 and set the result + context to NULL, or via a modern kernel+lib operating on a + file from a disk whose attributes were set by a kernel from + around 2006. In that latter case, the functions return a + length of 10 for the "unlabeled" context. Map both failures + to a return value of -1, and set errno to ENOTSUP in the + first case, and ENODATA in the latter. */ + if (r == 0) + scontext_err = ENOTSUP; + if (r == 10 && memcmp (ai->scontext, "unlabeled", 10) == 0) + { + freecon (ai->scontext); + scontext_err = ENODATA; + } +# endif + } +# endif + } + } + ai->scontext_err = scontext_err; + if (scontext_err) + ai->scontext = (char *) UNKNOWN_SECURITY_CONTEXT; +} + +# ifndef aclinfo_scontext_free +/* Free the pointer that file_has_aclinfo put into scontext. + However, do nothing if the argument is a null pointer; + This lets the caller replace the scontext member with a null pointer if it + is willing to own the member and call this function later. */ +void +aclinfo_scontext_free (char *scontext) +{ + if (scontext != UNKNOWN_SECURITY_CONTEXT) + { + if (is_smack_enabled ()) + free (scontext); + else if (scontext) + freecon (scontext); + } +} +# endif + +/* Free AI's heap storage. */ +void +aclinfo_free (struct aclinfo *ai) +{ + if (ai->buf != ai->u.__gl_acl_ch) + free (ai->buf); + aclinfo_scontext_free (ai->scontext); +} + /* Return 1 if given ACL in XDR format is non-trivial, 0 if it is trivial. -1 upon failure to determine it. Possibly change errno. Assume that the ACL is valid, except avoid undefined behavior even if invalid. @@ -151,86 +318,50 @@ acl_nfs4_nontrivial (uint32_t *xattr, ssize_t nbytes) and -1 (setting errno) on error. Note callers can determine if ACLs are not supported as errno is set in that case also. SB must be set to the stat buffer of NAME, - obtained through stat() or lstat(). */ - + obtained through stat() or lstat(). + Set *AI to the ACL info if available. + If FLAGS & AT_SYMLINK_FOLLOW, SB was gotten via stat and follow symlinks; + otherwise, SB was gotten vi lstat and do not follow them. */ int -file_has_acl (char const *name, struct stat const *sb) +file_has_aclinfo (char const *name, struct stat const *sb, + struct aclinfo *ai, int flags) { -#if USE_ACL - if (! S_ISLNK (sb->st_mode)) - { - -# if HAVE_LINUX_XATTR_H && HAVE_LISTXATTR - int initial_errno = errno; - - /* The max length of a trivial NFSv4 ACL is 6 words for owner, - 6 for group, 7 for everyone, all times 2 because there are - both allow and deny ACEs. There are 6 words for owner - because of type, flag, mask, wholen, "OWNER@"+pad and - similarly for group; everyone is another word to hold - "EVERYONE@". */ - typedef uint32_t trivial_NFSv4_xattr_buf[2 * (6 + 6 + 7)]; - - /* A buffer large enough to hold any trivial NFSv4 ACL, - and also useful as a small array of char. */ - union { - trivial_NFSv4_xattr_buf xattr; - char ch[sizeof (trivial_NFSv4_xattr_buf)]; - } stackbuf; - - char *listbuf = stackbuf.ch; - ssize_t listbufsize = sizeof stackbuf.ch; - char *heapbuf = NULL; - ssize_t listsize; - - /* Use listxattr first, as this means just one syscall in the - typical case where the file lacks an ACL. Try stackbuf - first, falling back on malloc if stackbuf is too small. */ - while ((listsize = listxattr (name, listbuf, listbufsize)) < 0 - && errno == ERANGE) - { - free (heapbuf); - ssize_t newsize = listxattr (name, NULL, 0); - if (newsize <= 0) - return newsize; - - /* Grow LISTBUFSIZE to at least NEWSIZE. Grow it by a - nontrivial amount too, to defend against denial of - service by an adversary that fiddles with ACLs. */ - bool overflow = ckd_add (&listbufsize, listbufsize, listbufsize >> 1); - listbufsize = MAX (listbufsize, newsize); - if (overflow || SIZE_MAX < listbufsize) - { - errno = ENOMEM; - return -1; - } - - listbuf = heapbuf = malloc (listbufsize); - if (!listbuf) - return -1; - } +#if USE_LINUX_XATTR + int initial_errno = errno; + get_aclinfo (name, ai, flags); + if (ai->size <= 0) + { + errno = ai->size < 0 ? ai->u.err : initial_errno; + return ai->size; + } + else + { /* In Fedora 39, a file can have both NFSv4 and POSIX ACLs, but if it has an NFSv4 ACL that's the one that matters. In earlier Fedora the two types of ACLs were mutually exclusive. Attempt to work correctly on both kinds of systems. */ - bool nfsv4_acl - = 0 < listsize && have_xattr (XATTR_NAME_NFSV4_ACL, listbuf, listsize); + bool nfsv4_acl = aclinfo_has_xattr (ai, XATTR_NAME_NFSV4_ACL); int ret - = (listsize <= 0 ? listsize + = (ai->size <= 0 ? ai->size : (nfsv4_acl - || have_xattr (XATTR_NAME_POSIX_ACL_ACCESS, listbuf, listsize) + || aclinfo_has_xattr (ai, XATTR_NAME_POSIX_ACL_ACCESS) || (S_ISDIR (sb->st_mode) - && have_xattr (XATTR_NAME_POSIX_ACL_DEFAULT, - listbuf, listsize)))); - free (heapbuf); + && aclinfo_has_xattr (ai, XATTR_NAME_POSIX_ACL_DEFAULT)))); /* If there is an NFSv4 ACL, follow up with a getxattr syscall to see whether the NFSv4 ACL is nontrivial. */ if (nfsv4_acl) { - ret = getxattr (name, XATTR_NAME_NFSV4_ACL, - stackbuf.xattr, sizeof stackbuf.xattr); + /* A buffer large enough to hold any trivial NFSv4 ACL. + The max length of a trivial NFSv4 ACL is 6 words for owner, + 6 for group, 7 for everyone, all times 2 because there are both + allow and deny ACEs. There are 6 words for owner because of + type, flag, mask, wholen, "OWNER@"+pad and similarly for group; + everyone is another word to hold "EVERYONE@". */ + uint32_t buf[2 * (6 + 6 + 7)]; + + ret = getxattr (name, XATTR_NAME_NFSV4_ACL, buf, sizeof buf); if (ret < 0) switch (errno) { @@ -240,7 +371,7 @@ file_has_acl (char const *name, struct stat const *sb) else { /* It looks like a trivial ACL, but investigate further. */ - ret = acl_nfs4_nontrivial (stackbuf.xattr, ret); + ret = acl_nfs4_nontrivial (buf, ret); if (ret < 0) { errno = EINVAL; @@ -252,8 +383,18 @@ file_has_acl (char const *name, struct stat const *sb) if (ret < 0) return - acl_errno_valid (errno); return ret; + } +#else + ai->size = -1; + ai->u.err = ENOTSUP; + ai->scontext = (char *) UNKNOWN_SECURITY_CONTEXT; + ai->scontext_err = ENOTSUP; +#endif -# elif HAVE_ACL_GET_FILE +#if USE_ACL + if (! S_ISLNK (sb->st_mode)) + { +# if HAVE_ACL_GET_FILE /* POSIX 1003.1e (draft 17 -- abandoned) specific version. */ /* Linux, FreeBSD, Mac OS X, IRIX, Tru64, Cygwin >= 2.5 */ @@ -682,3 +823,18 @@ file_has_acl (char const *name, struct stat const *sb) return 0; } + +/* Return 1 if NAME has a nontrivial access control list, + 0 if ACLs are not supported, or if NAME has no or only a base ACL, + and -1 (setting errno) on error. Note callers can determine + if ACLs are not supported as errno is set in that case also. + SB must be set to the stat buffer of NAME, + obtained through stat() or lstat(). */ +int +file_has_acl (char const *name, struct stat const *sb) +{ + struct aclinfo ai; + int r = file_has_aclinfo (name, sb, &ai, 0); + aclinfo_free (&ai); + return r; +} diff --git a/lib/se-selinux.in.h b/lib/se-selinux.in.h index 76d3762fd4..80795b107d 100644 --- a/lib/se-selinux.in.h +++ b/lib/se-selinux.in.h @@ -19,7 +19,7 @@ #endif @PRAGMA_COLUMNS@ -#if @HAVE_SELINUX_SELINUX_H@ +#if @USE_SELINUX_SELINUX_H@ #@INCLUDE_NEXT@ @NEXT_SELINUX_SELINUX_H@ diff --git a/m4/acl.m4 b/m4/acl.m4 index be88f1b831..4328bd20a1 100644 --- a/m4/acl.m4 +++ b/m4/acl.m4 @@ -1,5 +1,5 @@ # acl.m4 -# serial 31 +# serial 32 dnl Copyright (C) 2002, 2004-2024 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -15,9 +15,12 @@ AC_DEFUN([gl_FUNC_ACL_ARG], AC_ARG_ENABLE([acl], AS_HELP_STRING([[--disable-acl]], [do not support ACLs]), , [enable_acl=auto]) + AC_ARG_WITH([libsmack], + [AS_HELP_STRING([--without-libsmack], + [do not use libsmack, even on systems that have it])] + [], [with_libsmack=maybe]) ]) - AC_DEFUN_ONCE([gl_FUNC_ACL], [ AC_REQUIRE([gl_FUNC_ACL_ARG]) @@ -189,9 +192,35 @@ AC_DEFUN([gl_FILE_HAS_ACL], AC_CHECK_HEADERS_ONCE([linux/xattr.h]) AC_CHECK_FUNCS_ONCE([listxattr]) FILE_HAS_ACL_LIB= - AS_CASE([$enable_acl,$ac_cv_header_linux_xattr_h,$ac_cv_func_listxattr], - [no,*,*], [], - [*,yes,yes], [], + + gl_file_has_acl_uses_smack=no + AS_CASE([$enable_acl,$with_libsmack,$ac_cv_header_linux_xattr_h,$ac_cv_func_listxattr], + [no,* | *,no,*], [], + [*,*,yes,yes], + [AC_CHECK_HEADER([sys/smack.h], + [gl_saved_LIBS=$LIBS + AC_SEARCH_LIBS([smack_new_label_from_path], [smack], + [AC_DEFINE([HAVE_SMACK], [1], + [Define to 1 if libsmack is usable.]) + AS_CASE([$ac_cv_search_smack_new_label_from_path], + ["none required"], [], + [FILE_HAS_ACL_LIB=$ac_cv_search_new_label_from_path]) + gl_file_has_acl_uses_smack=yes], + [AS_CASE([$with_libsmack], + [yes], [AC_MSG_ERROR([libsmack not found or unusable])])]) + LIBS=$gl_saved_LIBS])]) + + gl_file_has_acl_uses_selinux=no + AS_CASE([$enable_acl,$with_selinux,$ac_cv_header_linux_xattr_h,$ac_cv_func_listxattr], + [no,* | *,no,*], [], + [*,*,yes,yes], + [gl_CHECK_HEADER_SELINUX_SELINUX_H + AS_IF([test "$USE_SELINUX_SELINUX_H" -ne 0 ], + [FILE_HAS_ACL_LIB="$FILE_HAS_ACL_LIB $LIB_SELINUX" + gl_file_has_acl_uses_selinux=yes])]) + + AS_CASE([$enable_acl,$gl_file_has_acl_uses_selinux,$gl_file_has_acl_uses_smack], + [no,* | *,yes,* | *,yes], [], [*], [dnl Set gl_need_lib_has_acl to a nonempty value, so that any dnl later gl_FUNC_ACL call will set FILE_HAS_ACL_LIB=$LIB_ACL. diff --git a/m4/selinux-selinux-h.m4 b/m4/selinux-selinux-h.m4 index 91fdc434f2..a141defef0 100644 --- a/m4/selinux-selinux-h.m4 +++ b/m4/selinux-selinux-h.m4 @@ -1,5 +1,5 @@ # selinux-selinux-h.m4 -# serial 8 -*- Autoconf -*- +# serial 9 -*- Autoconf -*- dnl Copyright (C) 2006-2007, 2009-2024 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -12,16 +12,8 @@ dnl with or without modifications, as long as this notice is preserved. AC_DEFUN([gl_HEADERS_SELINUX_SELINUX_H], [ - AC_REQUIRE([gl_LIBSELINUX]) + AC_REQUIRE([gl_CHECK_HEADER_SELINUX_SELINUX_H]) if test "$with_selinux" != no; then - AC_CHECK_HEADERS([selinux/selinux.h]) - - if test $ac_cv_header_selinux_selinux_h = yes; then - HAVE_SELINUX_SELINUX_H=1 - else - HAVE_SELINUX_SELINUX_H=0 - fi - if test "$ac_cv_header_selinux_selinux_h" = yes; then # We do have <selinux/selinux.h>, so do compile getfilecon.c # and arrange to use its wrappers. @@ -39,6 +31,22 @@ AC_DEFUN([gl_HEADERS_SELINUX_SELINUX_H], AC_DEFINE([fgetfilecon_raw], [rpl_fgetfilecon_raw], [Always use our fgetfilecon_raw wrapper.]) fi + fi +]) + +# Check for <selinux/selinux.h>, if necessary. + +AC_DEFUN([gl_CHECK_HEADER_SELINUX_SELINUX_H], +[ + AC_REQUIRE([gl_LIBSELINUX]) + if test "$with_selinux" != no; then + AC_CHECK_HEADERS_ONCE([selinux/selinux.h]) + + if test $ac_cv_header_selinux_selinux_h = yes; then + USE_SELINUX_SELINUX_H=1 + else + USE_SELINUX_SELINUX_H=0 + fi case "$ac_cv_search_setfilecon:$ac_cv_header_selinux_selinux_h" in no:*) # already warned @@ -50,9 +58,11 @@ AC_DEFUN([gl_HEADERS_SELINUX_SELINUX_H], else # Do as if <selinux/selinux.h> does not exist, even if # AC_CHECK_HEADERS_ONCE has already determined that it exists. - HAVE_SELINUX_SELINUX_H=0 + USE_SELINUX_SELINUX_H=0 fi - AC_SUBST([HAVE_SELINUX_SELINUX_H]) + AC_SUBST([USE_SELINUX_SELINUX_H]) + AC_DEFINE_UNQUOTED([USE_SELINUX_SELINUX_H], [$USE_SELINUX_SELINUX_H], + [Define to 1 if <selinux/selinux.h> should be used, to 0 otherwise.])]) ]) AC_DEFUN([gl_LIBSELINUX], diff --git a/modules/file-has-acl b/modules/file-has-acl index ec93313dfd..8adb310bd0 100644 --- a/modules/file-has-acl +++ b/modules/file-has-acl @@ -5,13 +5,16 @@ Files: lib/acl-internal.h lib/file-has-acl.c m4/acl.m4 +m4/selinux-selinux-h.m4 Depends-on: acl-permissions attribute +errno extern-inline minmax free-posix +ssize_t stat stdbool stdckdint diff --git a/modules/selinux-h b/modules/selinux-h index d4e89cc4fc..941673d1ee 100644 --- a/modules/selinux-h +++ b/modules/selinux-h @@ -34,11 +34,11 @@ selinux/selinux.h: se-selinux.in.h $(top_builddir)/config.status $(AM_V_GEN)$(MKDIR_P) '%reldir%/selinux' $(AM_V_at)$(SED_HEADER_STDOUT) \ -e 's|@''GUARD_PREFIX''@|${gl_include_guard_prefix}|g' \ - -e 's/@''HAVE_SELINUX_SELINUX_H''@/$(HAVE_SELINUX_SELINUX_H)/g' \ -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \ -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \ -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \ -e 's|@''NEXT_SELINUX_SELINUX_H''@|$(NEXT_SELINUX_SELINUX_H)|g' \ + -e 's/@''USE_SELINUX_SELINUX_H''@/$(USE_SELINUX_SELINUX_H)/g' \ $(srcdir)/se-selinux.in.h > $@-t $(AM_V_at)mv $@-t $@ MOSTLYCLEANFILES += selinux/selinux.h selinux/selinux.h-t diff --git a/tests/test-file-has-acl.c b/tests/test-file-has-acl.c index 1a10286cd2..c076660942 100644 --- a/tests/test-file-has-acl.c +++ b/tests/test-file-has-acl.c @@ -22,6 +22,7 @@ #include <signal.h> #include <stdio.h> +#include <string.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> @@ -64,6 +65,16 @@ main (int argc, char *argv[]) fprintf (stderr, "could not access the ACL of file \"%s\"\n", file); exit (EXIT_FAILURE); } + + struct aclinfo ai; + int reti = file_has_aclinfo (file, &statbuf, &ai, 0); + if (reti != ret) + { + fprintf (stderr, "file_has_aclinfo failed for \"%s\"\n", file); + exit (EXIT_FAILURE); + } + aclinfo_free (&ai); + printf ("%s\n", ret ? "yes" : "no"); } #else -- 2.43.0