You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3603 lines
114 KiB
3603 lines
114 KiB
7 years ago
|
From f733da5249b0b119cb551c73b322439bcbbc013a Mon Sep 17 00:00:00 2001
|
||
|
From: Pavel Raiskup <praiskup@redhat.com>
|
||
|
Date: Tue, 19 Feb 2013 10:41:10 +0100
|
||
|
Subject: [PATCH] x
|
||
|
|
||
|
---
|
||
|
build-aux/snippet/unused-parameter.h | 38 ++
|
||
|
gnu/Makefile.am | 93 +++-
|
||
|
gnu/acl-internal.h | 267 ++++++++++
|
||
|
gnu/acl.h | 30 ++
|
||
|
gnu/acl_entries.c | 77 +++
|
||
|
gnu/copy-acl.c | 620 +++++++++++++++++++++++
|
||
|
gnu/file-has-acl.c | 920 +++++++++++++++++++++++++++++++++++
|
||
|
gnu/getfilecon.c | 88 ++++
|
||
|
gnu/se-context.in.h | 30 ++
|
||
|
gnu/se-selinux.in.h | 99 ++++
|
||
|
gnu/selinux-at.c | 74 +++
|
||
|
gnu/selinux-at.h | 54 ++
|
||
|
gnu/set-mode-acl.c | 699 ++++++++++++++++++++++++++
|
||
|
m4/acl.m4 | 165 +++++++
|
||
|
m4/gnulib-comp.m4 | 27 +-
|
||
|
m4/selinux-context-h.m4 | 22 +
|
||
|
m4/selinux-selinux-h.m4 | 69 +++
|
||
|
17 files changed, 3365 insertions(+), 7 deletions(-)
|
||
|
create mode 100644 build-aux/snippet/unused-parameter.h
|
||
|
create mode 100644 gnu/acl-internal.h
|
||
|
create mode 100644 gnu/acl.h
|
||
|
create mode 100644 gnu/acl_entries.c
|
||
|
create mode 100644 gnu/copy-acl.c
|
||
|
create mode 100644 gnu/file-has-acl.c
|
||
|
create mode 100644 gnu/getfilecon.c
|
||
|
create mode 100644 gnu/se-context.in.h
|
||
|
create mode 100644 gnu/se-selinux.in.h
|
||
|
create mode 100644 gnu/selinux-at.c
|
||
|
create mode 100644 gnu/selinux-at.h
|
||
|
create mode 100644 gnu/set-mode-acl.c
|
||
|
create mode 100644 m4/acl.m4
|
||
|
create mode 100644 m4/selinux-context-h.m4
|
||
|
create mode 100644 m4/selinux-selinux-h.m4
|
||
|
|
||
|
diff --git a/build-aux/snippet/unused-parameter.h b/build-aux/snippet/unused-parameter.h
|
||
|
new file mode 100644
|
||
|
index 0000000..6b60482
|
||
|
--- /dev/null
|
||
|
+++ b/build-aux/snippet/unused-parameter.h
|
||
|
@@ -0,0 +1,38 @@
|
||
|
+/* -*- buffer-read-only: t -*- vi: set ro: */
|
||
|
+/* DO NOT EDIT! GENERATED AUTOMATICALLY! */
|
||
|
+/* A C macro for declaring that specific function parameters are not used.
|
||
|
+ Copyright (C) 2008-2012 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 <http://www.gnu.org/licenses/>. */
|
||
|
+
|
||
|
+/* _GL_UNUSED_PARAMETER is a marker that can be appended to function parameter
|
||
|
+ declarations for parameters that are not used. This helps to reduce
|
||
|
+ warnings, such as from GCC -Wunused-parameter. The syntax is as follows:
|
||
|
+ type param _GL_UNUSED_PARAMETER
|
||
|
+ or more generally
|
||
|
+ param_decl _GL_UNUSED_PARAMETER
|
||
|
+ For example:
|
||
|
+ int param _GL_UNUSED_PARAMETER
|
||
|
+ int *(*param)(void) _GL_UNUSED_PARAMETER
|
||
|
+ Other possible, but obscure and discouraged syntaxes:
|
||
|
+ int _GL_UNUSED_PARAMETER *(*param)(void)
|
||
|
+ _GL_UNUSED_PARAMETER int *(*param)(void)
|
||
|
+ */
|
||
|
+#ifndef _GL_UNUSED_PARAMETER
|
||
|
+# if __GNUC__ >= 3 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7)
|
||
|
+# define _GL_UNUSED_PARAMETER __attribute__ ((__unused__))
|
||
|
+# else
|
||
|
+# define _GL_UNUSED_PARAMETER
|
||
|
+# endif
|
||
|
+#endif
|
||
|
diff --git a/gnu/Makefile.am b/gnu/Makefile.am
|
||
|
index 06eb0d9..77d75d2 100644
|
||
|
--- a/gnu/Makefile.am
|
||
|
+++ b/gnu/Makefile.am
|
||
|
@@ -1,6 +1,3 @@
|
||
|
-# -*- buffer-read-only: t -*- vi: set ro:
|
||
|
-# DO NOT EDIT! GENERATED AUTOMATICALLY!
|
||
|
-## DO NOT EDIT! GENERATED AUTOMATICALLY!
|
||
|
## Process this file with automake to produce Makefile.in.
|
||
|
# Copyright (C) 2002-2011 Free Software Foundation, Inc.
|
||
|
#
|
||
|
@@ -38,8 +35,17 @@ libgnu_a_LIBADD = $(gl_LIBOBJS)
|
||
|
libgnu_a_DEPENDENCIES = $(gl_LIBOBJS)
|
||
|
EXTRA_libgnu_a_SOURCES =
|
||
|
|
||
|
-## begin gnulib module alloca
|
||
|
+## begin gnulib module acl
|
||
|
+
|
||
|
+libgnu_a_SOURCES += set-mode-acl.c copy-acl.c file-has-acl.c
|
||
|
+
|
||
|
+EXTRA_DIST += acl-internal.h acl.h acl_entries.c
|
||
|
|
||
|
+EXTRA_libgnu_a_SOURCES += acl_entries.c
|
||
|
+
|
||
|
+## end gnulib module acl
|
||
|
+
|
||
|
+## begin gnulib module alloca
|
||
|
|
||
|
EXTRA_DIST += alloca.c
|
||
|
|
||
|
@@ -179,6 +185,31 @@ EXTRA_DIST += $(top_srcdir)/build-aux/c++defs.h
|
||
|
|
||
|
## end gnulib module c++defs
|
||
|
|
||
|
+## begin gnulib module snippet/unused-parameter
|
||
|
+
|
||
|
+# The BUILT_SOURCES created by this Makefile snippet are not used via #include
|
||
|
+# statements but through direct file reference. Therefore this snippet must be
|
||
|
+# present in all Makefile.am that need it. This is ensured by the applicability
|
||
|
+# 'all' defined above.
|
||
|
+
|
||
|
+BUILT_SOURCES += unused-parameter.h
|
||
|
+# The unused-parameter.h that gets inserted into generated .h files is the same
|
||
|
+# as build-aux/snippet/unused-parameter.h, except that it has the copyright
|
||
|
+# header cut off.
|
||
|
+unused-parameter.h: $(top_srcdir)/build-aux/snippet/unused-parameter.h
|
||
|
+ $(AM_V_GEN)rm -f $@-t $@ && \
|
||
|
+ sed -n -e '/GL_UNUSED_PARAMETER/,$$p' \
|
||
|
+ < $(top_srcdir)/build-aux/snippet/unused-parameter.h \
|
||
|
+ > $@-t && \
|
||
|
+ mv $@-t $@
|
||
|
+MOSTLYCLEANFILES += unused-parameter.h unused-parameter.h-t
|
||
|
+
|
||
|
+UNUSED_PARAMETER_H=unused-parameter.h
|
||
|
+
|
||
|
+EXTRA_DIST += $(top_srcdir)/build-aux/snippet/unused-parameter.h
|
||
|
+
|
||
|
+## end gnulib module snippet/unused-parameter
|
||
|
+
|
||
|
## begin gnulib module c-ctype
|
||
|
|
||
|
libgnu_a_SOURCES += c-ctype.h c-ctype.c
|
||
|
@@ -1386,6 +1417,60 @@ EXTRA_libgnu_a_SOURCES += savedir.c
|
||
|
|
||
|
## end gnulib module savedir
|
||
|
|
||
|
+## begin gnulib module selinux-at
|
||
|
+
|
||
|
+
|
||
|
+EXTRA_DIST += at-func.c selinux-at.c selinux-at.h
|
||
|
+
|
||
|
+EXTRA_libgnu_a_SOURCES += at-func.c selinux-at.c
|
||
|
+
|
||
|
+## end gnulib module selinux-at
|
||
|
+
|
||
|
+## begin gnulib module selinux-h
|
||
|
+
|
||
|
+libgnu_a_SOURCES += se-context.in.h se-selinux.in.h
|
||
|
+
|
||
|
+BUILT_SOURCES += selinux/selinux.h
|
||
|
+selinux/selinux.h: se-selinux.in.h $(top_builddir)/config.status $(UNUSED_PARAMETER_H)
|
||
|
+ $(AM_V_at)$(MKDIR_P) selinux
|
||
|
+ $(AM_V_GEN)rm -f $@-t $@ && \
|
||
|
+ { echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */' && \
|
||
|
+ sed -e 's|@''GUARD_PREFIX''@|GL|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 '/definition of _GL_UNUSED_PARAMETER/r $(UNUSED_PARAMETER_H)' \
|
||
|
+ < $(srcdir)/se-selinux.in.h; \
|
||
|
+ } > $@-t && \
|
||
|
+ chmod a-x $@-t && \
|
||
|
+ mv $@-t $@
|
||
|
+MOSTLYCLEANFILES += selinux/selinux.h selinux/selinux.h-t
|
||
|
+
|
||
|
+BUILT_SOURCES += $(SELINUX_CONTEXT_H)
|
||
|
+if GL_GENERATE_SELINUX_CONTEXT_H
|
||
|
+selinux/context.h: se-context.in.h $(top_builddir)/config.status $(UNUSED_PARAMETER_H)
|
||
|
+ $(AM_V_at)$(MKDIR_P) selinux
|
||
|
+ $(AM_V_GEN)rm -f $@-t $@ && \
|
||
|
+ { echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */' && \
|
||
|
+ sed -e '/definition of _GL_UNUSED_PARAMETER/r $(UNUSED_PARAMETER_H)' \
|
||
|
+ < $(srcdir)/se-context.in.h; \
|
||
|
+ } > $@-t && \
|
||
|
+ chmod a-x $@-t && \
|
||
|
+ mv $@-t $@
|
||
|
+else
|
||
|
+selinux/context.h: $(top_builddir)/config.status
|
||
|
+ rm -f $@
|
||
|
+endif
|
||
|
+MOSTLYCLEANFILES += selinux/context.h selinux/context.h-t
|
||
|
+MOSTLYCLEANDIRS += selinux
|
||
|
+
|
||
|
+EXTRA_DIST += getfilecon.c
|
||
|
+
|
||
|
+EXTRA_libgnu_a_SOURCES += getfilecon.c
|
||
|
+
|
||
|
+## end gnulib module selinux-h
|
||
|
+
|
||
|
## begin gnulib module setenv
|
||
|
|
||
|
|
||
|
diff --git a/gnu/acl-internal.h b/gnu/acl-internal.h
|
||
|
new file mode 100644
|
||
|
index 0000000..07309e0
|
||
|
--- /dev/null
|
||
|
+++ b/gnu/acl-internal.h
|
||
|
@@ -0,0 +1,267 @@
|
||
|
+/* -*- buffer-read-only: t -*- vi: set ro: */
|
||
|
+/* DO NOT EDIT! GENERATED AUTOMATICALLY! */
|
||
|
+/* Internal implementation of access control lists.
|
||
|
+
|
||
|
+ Copyright (C) 2002-2003, 2005-2012 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 <http://www.gnu.org/licenses/>.
|
||
|
+
|
||
|
+ Written by Paul Eggert, Andreas Grünbacher, and Bruno Haible. */
|
||
|
+
|
||
|
+#include "acl.h"
|
||
|
+
|
||
|
+#include <stdbool.h>
|
||
|
+#include <stdlib.h>
|
||
|
+
|
||
|
+/* All systems define the ACL related API in <sys/acl.h>. */
|
||
|
+#if HAVE_SYS_ACL_H
|
||
|
+# include <sys/acl.h>
|
||
|
+#endif
|
||
|
+#if defined HAVE_FACL && ! defined GETACLCNT && defined ACL_CNT
|
||
|
+# define GETACLCNT ACL_CNT
|
||
|
+#endif
|
||
|
+
|
||
|
+/* On Linux, additional ACL related API is available in <acl/libacl.h>. */
|
||
|
+#ifdef HAVE_ACL_LIBACL_H
|
||
|
+# include <acl/libacl.h>
|
||
|
+#endif
|
||
|
+
|
||
|
+/* On HP-UX >= 11.11, additional ACL API is available in <aclv.h>. */
|
||
|
+#if HAVE_ACLV_H
|
||
|
+# include <sys/types.h>
|
||
|
+# include <aclv.h>
|
||
|
+/* HP-UX 11.11 lacks these declarations. */
|
||
|
+extern int acl (char *, int, int, struct acl *);
|
||
|
+extern int aclsort (int, int, struct acl *);
|
||
|
+#endif
|
||
|
+
|
||
|
+#include "error.h"
|
||
|
+#include "quote.h"
|
||
|
+
|
||
|
+#include <errno.h>
|
||
|
+#ifndef ENOSYS
|
||
|
+# define ENOSYS (-1)
|
||
|
+#endif
|
||
|
+#ifndef ENOTSUP
|
||
|
+# define ENOTSUP (-1)
|
||
|
+#endif
|
||
|
+
|
||
|
+#include <limits.h>
|
||
|
+#ifndef MIN
|
||
|
+# define MIN(a,b) ((a) < (b) ? (a) : (b))
|
||
|
+#endif
|
||
|
+
|
||
|
+#ifndef SIZE_MAX
|
||
|
+# define SIZE_MAX ((size_t) -1)
|
||
|
+#endif
|
||
|
+
|
||
|
+#ifndef HAVE_FCHMOD
|
||
|
+# define HAVE_FCHMOD false
|
||
|
+# define fchmod(fd, mode) (-1)
|
||
|
+#endif
|
||
|
+
|
||
|
+/* Recognize some common errors such as from an NFS mount that does
|
||
|
+ not support ACLs, even when local drives do. */
|
||
|
+#if defined __APPLE__ && defined __MACH__ /* Mac OS X */
|
||
|
+# define ACL_NOT_WELL_SUPPORTED(Err) \
|
||
|
+ ((Err) == ENOTSUP || (Err) == ENOSYS || (Err) == EINVAL || (Err) == EBUSY || (Err) == ENOENT)
|
||
|
+#elif defined EOPNOTSUPP /* Tru64 NFS */
|
||
|
+# define ACL_NOT_WELL_SUPPORTED(Err) \
|
||
|
+ ((Err) == ENOTSUP || (Err) == ENOSYS || (Err) == EINVAL || (Err) == EBUSY || (Err) == EOPNOTSUPP)
|
||
|
+#else
|
||
|
+# define ACL_NOT_WELL_SUPPORTED(Err) \
|
||
|
+ ((Err) == ENOTSUP || (Err) == ENOSYS || (Err) == EINVAL || (Err) == EBUSY)
|
||
|
+#endif
|
||
|
+
|
||
|
+#if USE_ACL
|
||
|
+
|
||
|
+# if HAVE_ACL_GET_FILE
|
||
|
+/* POSIX 1003.1e (draft 17 -- abandoned) specific version. */
|
||
|
+/* Linux, FreeBSD, Mac OS X, IRIX, Tru64 */
|
||
|
+
|
||
|
+# ifndef MIN_ACL_ENTRIES
|
||
|
+# define MIN_ACL_ENTRIES 4
|
||
|
+# endif
|
||
|
+
|
||
|
+/* POSIX 1003.1e (draft 17) */
|
||
|
+# ifdef HAVE_ACL_GET_FD
|
||
|
+/* Most platforms have a 1-argument acl_get_fd, only OSF/1 has a 2-argument
|
||
|
+ macro(!). */
|
||
|
+# if HAVE_ACL_FREE_TEXT /* OSF/1 */
|
||
|
+static inline acl_t
|
||
|
+rpl_acl_get_fd (int fd)
|
||
|
+{
|
||
|
+ return acl_get_fd (fd, ACL_TYPE_ACCESS);
|
||
|
+}
|
||
|
+# undef acl_get_fd
|
||
|
+# define acl_get_fd rpl_acl_get_fd
|
||
|
+# endif
|
||
|
+# else
|
||
|
+# define HAVE_ACL_GET_FD false
|
||
|
+# undef acl_get_fd
|
||
|
+# define acl_get_fd(fd) (NULL)
|
||
|
+# endif
|
||
|
+
|
||
|
+/* POSIX 1003.1e (draft 17) */
|
||
|
+# ifdef HAVE_ACL_SET_FD
|
||
|
+/* Most platforms have a 2-argument acl_set_fd, only OSF/1 has a 3-argument
|
||
|
+ macro(!). */
|
||
|
+# if HAVE_ACL_FREE_TEXT /* OSF/1 */
|
||
|
+static inline int
|
||
|
+rpl_acl_set_fd (int fd, acl_t acl)
|
||
|
+{
|
||
|
+ return acl_set_fd (fd, ACL_TYPE_ACCESS, acl);
|
||
|
+}
|
||
|
+# undef acl_set_fd
|
||
|
+# define acl_set_fd rpl_acl_set_fd
|
||
|
+# endif
|
||
|
+# else
|
||
|
+# define HAVE_ACL_SET_FD false
|
||
|
+# undef acl_set_fd
|
||
|
+# define acl_set_fd(fd, acl) (-1)
|
||
|
+# endif
|
||
|
+
|
||
|
+/* POSIX 1003.1e (draft 13) */
|
||
|
+# if ! HAVE_ACL_FREE_TEXT
|
||
|
+# define acl_free_text(buf) acl_free (buf)
|
||
|
+# endif
|
||
|
+
|
||
|
+/* Linux-specific */
|
||
|
+# ifndef HAVE_ACL_EXTENDED_FILE
|
||
|
+# define HAVE_ACL_EXTENDED_FILE false
|
||
|
+# define acl_extended_file(name) (-1)
|
||
|
+# endif
|
||
|
+
|
||
|
+/* Linux-specific */
|
||
|
+# ifndef HAVE_ACL_FROM_MODE
|
||
|
+# define HAVE_ACL_FROM_MODE false
|
||
|
+# define acl_from_mode(mode) (NULL)
|
||
|
+# endif
|
||
|
+
|
||
|
+/* 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. */
|
||
|
+# if (HAVE_ACL_COPY_EXT_NATIVE && HAVE_ACL_CREATE_ENTRY_NP) || defined __sgi /* Mac OS X, IRIX */
|
||
|
+# define MODE_INSIDE_ACL 0
|
||
|
+# else
|
||
|
+# define MODE_INSIDE_ACL 1
|
||
|
+# endif
|
||
|
+
|
||
|
+/* Return the number of entries in ACL.
|
||
|
+ Return -1 and set errno upon failure to determine it. */
|
||
|
+/* Define a replacement for acl_entries if needed. (Only Linux has it.) */
|
||
|
+# if !HAVE_ACL_ENTRIES
|
||
|
+# define acl_entries rpl_acl_entries
|
||
|
+extern int acl_entries (acl_t);
|
||
|
+# endif
|
||
|
+
|
||
|
+# if HAVE_ACL_TYPE_EXTENDED /* Mac OS X */
|
||
|
+/* ACL is an ACL, from a file, stored as type ACL_TYPE_EXTENDED.
|
||
|
+ Return 1 if the given ACL is non-trivial.
|
||
|
+ Return 0 if it is trivial. */
|
||
|
+extern int acl_extended_nontrivial (acl_t);
|
||
|
+# else
|
||
|
+/* ACL is an ACL, from a file, stored as type ACL_TYPE_ACCESS.
|
||
|
+ Return 1 if the given ACL is non-trivial.
|
||
|
+ Return 0 if it is trivial, i.e. equivalent to a simple stat() mode.
|
||
|
+ Return -1 and set errno upon failure to determine it. */
|
||
|
+extern int acl_access_nontrivial (acl_t);
|
||
|
+# endif
|
||
|
+
|
||
|
+# 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. */
|
||
|
+# if defined __CYGWIN__ /* Cygwin */
|
||
|
+# define MODE_INSIDE_ACL 0
|
||
|
+# else /* Solaris */
|
||
|
+# define MODE_INSIDE_ACL 1
|
||
|
+# endif
|
||
|
+
|
||
|
+/* 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, aclent_t *entries);
|
||
|
+
|
||
|
+# ifdef ACE_GETACL /* Solaris 10 */
|
||
|
+
|
||
|
+/* Test an ACL retrieved with ACE_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. */
|
||
|
+extern int acl_ace_nontrivial (int count, ace_t *entries);
|
||
|
+
|
||
|
+/* Definitions for when the built executable is executed on Solaris 10
|
||
|
+ (newer version) or Solaris 11. */
|
||
|
+/* For a_type. */
|
||
|
+# define OLD_ALLOW 0
|
||
|
+# define OLD_DENY 1
|
||
|
+# define NEW_ACE_ACCESS_ALLOWED_ACE_TYPE 0 /* replaces ALLOW */
|
||
|
+# define NEW_ACE_ACCESS_DENIED_ACE_TYPE 1 /* replaces DENY */
|
||
|
+/* For a_flags. */
|
||
|
+# define OLD_ACE_OWNER 0x0100
|
||
|
+# define OLD_ACE_GROUP 0x0200
|
||
|
+# define OLD_ACE_OTHER 0x0400
|
||
|
+# define NEW_ACE_OWNER 0x1000
|
||
|
+# define NEW_ACE_GROUP 0x2000
|
||
|
+# define NEW_ACE_IDENTIFIER_GROUP 0x0040
|
||
|
+# define NEW_ACE_EVERYONE 0x4000
|
||
|
+/* For a_access_mask. */
|
||
|
+# define NEW_ACE_READ_DATA 0x001 /* corresponds to 'r' */
|
||
|
+# define NEW_ACE_WRITE_DATA 0x002 /* corresponds to 'w' */
|
||
|
+# define NEW_ACE_APPEND_DATA 0x004
|
||
|
+# define NEW_ACE_READ_NAMED_ATTRS 0x008
|
||
|
+# define NEW_ACE_WRITE_NAMED_ATTRS 0x010
|
||
|
+# define NEW_ACE_EXECUTE 0x020
|
||
|
+# define NEW_ACE_DELETE_CHILD 0x040
|
||
|
+# define NEW_ACE_READ_ATTRIBUTES 0x080
|
||
|
+# define NEW_ACE_WRITE_ATTRIBUTES 0x100
|
||
|
+# define NEW_ACE_DELETE 0x10000
|
||
|
+# define NEW_ACE_READ_ACL 0x20000
|
||
|
+# define NEW_ACE_WRITE_ACL 0x40000
|
||
|
+# define NEW_ACE_WRITE_OWNER 0x80000
|
||
|
+# define NEW_ACE_SYNCHRONIZE 0x100000
|
||
|
+
|
||
|
+# endif
|
||
|
+
|
||
|
+# elif HAVE_GETACL /* HP-UX */
|
||
|
+
|
||
|
+/* 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_entry *entries, struct stat *sb);
|
||
|
+
|
||
|
+# if HAVE_ACLV_H /* HP-UX >= 11.11 */
|
||
|
+
|
||
|
+/* 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 aclv_nontrivial (int count, struct acl *entries);
|
||
|
+
|
||
|
+# endif
|
||
|
+
|
||
|
+# elif HAVE_ACLX_GET && 0 /* AIX */
|
||
|
+
|
||
|
+/* TODO */
|
||
|
+
|
||
|
+# elif 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. */
|
||
|
+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/gnu/acl.h b/gnu/acl.h
|
||
|
new file mode 100644
|
||
|
index 0000000..d808a90
|
||
|
--- /dev/null
|
||
|
+++ b/gnu/acl.h
|
||
|
@@ -0,0 +1,30 @@
|
||
|
+/* -*- buffer-read-only: t -*- vi: set ro: */
|
||
|
+/* DO NOT EDIT! GENERATED AUTOMATICALLY! */
|
||
|
+/* acl.c - access control lists
|
||
|
+
|
||
|
+ Copyright (C) 2002, 2008-2012 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 <http://www.gnu.org/licenses/>.
|
||
|
+
|
||
|
+ Written by Paul Eggert. */
|
||
|
+
|
||
|
+#include <sys/types.h>
|
||
|
+#include <sys/stat.h>
|
||
|
+
|
||
|
+int file_has_acl (char const *, struct stat const *);
|
||
|
+int qset_acl (char const *, int, mode_t);
|
||
|
+int set_acl (char const *, int, mode_t);
|
||
|
+int qcopy_acl (char const *, int, char const *, int, mode_t);
|
||
|
+int copy_acl (char const *, int, char const *, int, mode_t);
|
||
|
+int chmod_or_fchmod (char const *, int, mode_t);
|
||
|
diff --git a/gnu/acl_entries.c b/gnu/acl_entries.c
|
||
|
new file mode 100644
|
||
|
index 0000000..11adc22
|
||
|
--- /dev/null
|
||
|
+++ b/gnu/acl_entries.c
|
||
|
@@ -0,0 +1,77 @@
|
||
|
+/* -*- buffer-read-only: t -*- vi: set ro: */
|
||
|
+/* DO NOT EDIT! GENERATED AUTOMATICALLY! */
|
||
|
+/* Return the number of entries in an ACL.
|
||
|
+
|
||
|
+ Copyright (C) 2002-2003, 2005-2012 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 <http://www.gnu.org/licenses/>.
|
||
|
+
|
||
|
+ Written by Paul Eggert and Andreas Gruenbacher. */
|
||
|
+
|
||
|
+#include <config.h>
|
||
|
+
|
||
|
+#include "acl-internal.h"
|
||
|
+
|
||
|
+/* This file assumes POSIX-draft like ACLs
|
||
|
+ (Linux, FreeBSD, Mac OS X, IRIX, Tru64). */
|
||
|
+
|
||
|
+/* Return the number of entries in ACL.
|
||
|
+ Return -1 and set errno upon failure to determine it. */
|
||
|
+
|
||
|
+int
|
||
|
+acl_entries (acl_t acl)
|
||
|
+{
|
||
|
+ int count = 0;
|
||
|
+
|
||
|
+ if (acl != NULL)
|
||
|
+ {
|
||
|
+#if HAVE_ACL_FIRST_ENTRY /* Linux, FreeBSD, Mac OS X */
|
||
|
+# if HAVE_ACL_TYPE_EXTENDED /* Mac OS X */
|
||
|
+ /* acl_get_entry returns 0 when it successfully fetches an entry,
|
||
|
+ and -1/EINVAL at the end. */
|
||
|
+ acl_entry_t ace;
|
||
|
+ int got_one;
|
||
|
+
|
||
|
+ for (got_one = acl_get_entry (acl, ACL_FIRST_ENTRY, &ace);
|
||
|
+ got_one >= 0;
|
||
|
+ got_one = acl_get_entry (acl, ACL_NEXT_ENTRY, &ace))
|
||
|
+ count++;
|
||
|
+# else /* Linux, FreeBSD */
|
||
|
+ /* acl_get_entry returns 1 when it successfully fetches an entry,
|
||
|
+ and 0 at the end. */
|
||
|
+ acl_entry_t ace;
|
||
|
+ int got_one;
|
||
|
+
|
||
|
+ for (got_one = acl_get_entry (acl, ACL_FIRST_ENTRY, &ace);
|
||
|
+ got_one > 0;
|
||
|
+ got_one = acl_get_entry (acl, ACL_NEXT_ENTRY, &ace))
|
||
|
+ count++;
|
||
|
+ if (got_one < 0)
|
||
|
+ return -1;
|
||
|
+# endif
|
||
|
+#else /* IRIX, Tru64 */
|
||
|
+# if HAVE_ACL_TO_SHORT_TEXT /* IRIX */
|
||
|
+ /* Don't use acl_get_entry: it is undocumented. */
|
||
|
+ count = acl->acl_cnt;
|
||
|
+# endif
|
||
|
+# if HAVE_ACL_FREE_TEXT /* Tru64 */
|
||
|
+ /* Don't use acl_get_entry: it takes only one argument and does not
|
||
|
+ work. */
|
||
|
+ count = acl->acl_num;
|
||
|
+# endif
|
||
|
+#endif
|
||
|
+ }
|
||
|
+
|
||
|
+ return count;
|
||
|
+}
|
||
|
diff --git a/gnu/copy-acl.c b/gnu/copy-acl.c
|
||
|
new file mode 100644
|
||
|
index 0000000..a4d82f7
|
||
|
--- /dev/null
|
||
|
+++ b/gnu/copy-acl.c
|
||
|
@@ -0,0 +1,620 @@
|
||
|
+/* -*- buffer-read-only: t -*- vi: set ro: */
|
||
|
+/* DO NOT EDIT! GENERATED AUTOMATICALLY! */
|
||
|
+/* copy-acl.c - copy access control list from one file to another file
|
||
|
+
|
||
|
+ Copyright (C) 2002-2003, 2005-2012 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 <http://www.gnu.org/licenses/>.
|
||
|
+
|
||
|
+ Written by Paul Eggert, Andreas Grünbacher, and Bruno Haible. */
|
||
|
+
|
||
|
+#include <config.h>
|
||
|
+
|
||
|
+#include "acl.h"
|
||
|
+
|
||
|
+#include "acl-internal.h"
|
||
|
+
|
||
|
+#include "gettext.h"
|
||
|
+#define _(msgid) gettext (msgid)
|
||
|
+
|
||
|
+
|
||
|
+/* Copy access control lists from one file to another. If SOURCE_DESC is
|
||
|
+ a valid file descriptor, use file descriptor operations, else use
|
||
|
+ filename based operations on SRC_NAME. Likewise for DEST_DESC and
|
||
|
+ DST_NAME.
|
||
|
+ If access control lists are not available, fchmod the target file to
|
||
|
+ MODE. Also sets the non-permission bits of the destination file
|
||
|
+ (S_ISUID, S_ISGID, S_ISVTX) to those from MODE if any are set.
|
||
|
+ Return 0 if successful.
|
||
|
+ Return -2 and set errno for an error relating to the source file.
|
||
|
+ Return -1 and set errno for an error relating to the destination file. */
|
||
|
+
|
||
|
+int
|
||
|
+qcopy_acl (const char *src_name, int source_desc, const char *dst_name,
|
||
|
+ int dest_desc, mode_t mode)
|
||
|
+{
|
||
|
+#if USE_ACL && HAVE_ACL_GET_FILE
|
||
|
+ /* POSIX 1003.1e (draft 17 -- abandoned) specific version. */
|
||
|
+ /* Linux, FreeBSD, Mac OS X, IRIX, Tru64 */
|
||
|
+# if !HAVE_ACL_TYPE_EXTENDED
|
||
|
+ /* Linux, FreeBSD, IRIX, Tru64 */
|
||
|
+
|
||
|
+ acl_t acl;
|
||
|
+ int ret;
|
||
|
+
|
||
|
+ if (HAVE_ACL_GET_FD && source_desc != -1)
|
||
|
+ acl = acl_get_fd (source_desc);
|
||
|
+ else
|
||
|
+ acl = acl_get_file (src_name, ACL_TYPE_ACCESS);
|
||
|
+ if (acl == NULL)
|
||
|
+ {
|
||
|
+ if (ACL_NOT_WELL_SUPPORTED (errno))
|
||
|
+ return qset_acl (dst_name, dest_desc, mode);
|
||
|
+ else
|
||
|
+ return -2;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (HAVE_ACL_SET_FD && dest_desc != -1)
|
||
|
+ ret = acl_set_fd (dest_desc, acl);
|
||
|
+ else
|
||
|
+ ret = acl_set_file (dst_name, ACL_TYPE_ACCESS, acl);
|
||
|
+ if (ret != 0)
|
||
|
+ {
|
||
|
+ int saved_errno = errno;
|
||
|
+
|
||
|
+ if (ACL_NOT_WELL_SUPPORTED (errno) && !acl_access_nontrivial (acl))
|
||
|
+ {
|
||
|
+ acl_free (acl);
|
||
|
+ return chmod_or_fchmod (dst_name, dest_desc, mode);
|
||
|
+ }
|
||
|
+ else
|
||
|
+ {
|
||
|
+ acl_free (acl);
|
||
|
+ chmod_or_fchmod (dst_name, dest_desc, mode);
|
||
|
+ errno = saved_errno;
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ else
|
||
|
+ acl_free (acl);
|
||
|
+
|
||
|
+ if (!MODE_INSIDE_ACL || (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. */
|
||
|
+
|
||
|
+ if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (S_ISDIR (mode))
|
||
|
+ {
|
||
|
+ acl = acl_get_file (src_name, ACL_TYPE_DEFAULT);
|
||
|
+ if (acl == NULL)
|
||
|
+ return -2;
|
||
|
+
|
||
|
+ if (acl_set_file (dst_name, ACL_TYPE_DEFAULT, acl))
|
||
|
+ {
|
||
|
+ int saved_errno = errno;
|
||
|
+
|
||
|
+ acl_free (acl);
|
||
|
+ errno = saved_errno;
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+ else
|
||
|
+ acl_free (acl);
|
||
|
+ }
|
||
|
+ return 0;
|
||
|
+
|
||
|
+# else /* HAVE_ACL_TYPE_EXTENDED */
|
||
|
+ /* Mac OS X */
|
||
|
+
|
||
|
+ /* On Mac OS X, acl_get_file (name, ACL_TYPE_ACCESS)
|
||
|
+ and acl_get_file (name, ACL_TYPE_DEFAULT)
|
||
|
+ always return NULL / EINVAL. You have to use
|
||
|
+ acl_get_file (name, ACL_TYPE_EXTENDED)
|
||
|
+ or acl_get_fd (open (name, ...))
|
||
|
+ to retrieve an ACL.
|
||
|
+ On the other hand,
|
||
|
+ acl_set_file (name, ACL_TYPE_ACCESS, acl)
|
||
|
+ and acl_set_file (name, ACL_TYPE_DEFAULT, acl)
|
||
|
+ have the same effect as
|
||
|
+ acl_set_file (name, ACL_TYPE_EXTENDED, acl):
|
||
|
+ Each of these calls sets the file's ACL. */
|
||
|
+
|
||
|
+ acl_t acl;
|
||
|
+ int ret;
|
||
|
+
|
||
|
+ if (HAVE_ACL_GET_FD && source_desc != -1)
|
||
|
+ acl = acl_get_fd (source_desc);
|
||
|
+ else
|
||
|
+ acl = acl_get_file (src_name, ACL_TYPE_EXTENDED);
|
||
|
+ if (acl == NULL)
|
||
|
+ {
|
||
|
+ if (ACL_NOT_WELL_SUPPORTED (errno))
|
||
|
+ return qset_acl (dst_name, dest_desc, mode);
|
||
|
+ else
|
||
|
+ return -2;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (HAVE_ACL_SET_FD && dest_desc != -1)
|
||
|
+ ret = acl_set_fd (dest_desc, acl);
|
||
|
+ else
|
||
|
+ ret = acl_set_file (dst_name, ACL_TYPE_EXTENDED, acl);
|
||
|
+ if (ret != 0)
|
||
|
+ {
|
||
|
+ int saved_errno = errno;
|
||
|
+
|
||
|
+ if (ACL_NOT_WELL_SUPPORTED (errno) && !acl_extended_nontrivial (acl))
|
||
|
+ {
|
||
|
+ acl_free (acl);
|
||
|
+ return chmod_or_fchmod (dst_name, dest_desc, mode);
|
||
|
+ }
|
||
|
+ else
|
||
|
+ {
|
||
|
+ acl_free (acl);
|
||
|
+ chmod_or_fchmod (dst_name, dest_desc, mode);
|
||
|
+ errno = saved_errno;
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ else
|
||
|
+ acl_free (acl);
|
||
|
+
|
||
|
+ /* Since !MODE_INSIDE_ACL, we have to call chmod explicitly. */
|
||
|
+ return chmod_or_fchmod (dst_name, dest_desc, mode);
|
||
|
+
|
||
|
+# endif
|
||
|
+
|
||
|
+#elif USE_ACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
|
||
|
+
|
||
|
+ /* Solaris 2.5 through Solaris 10, Cygwin, and contemporaneous versions
|
||
|
+ of Unixware. The acl() call returns the access and default ACL both
|
||
|
+ at once. */
|
||
|
+# ifdef ACE_GETACL
|
||
|
+ int ace_count;
|
||
|
+ ace_t *ace_entries;
|
||
|
+# endif
|
||
|
+ int count;
|
||
|
+ aclent_t *entries;
|
||
|
+ int did_chmod;
|
||
|
+ int saved_errno;
|
||
|
+ int ret;
|
||
|
+
|
||
|
+# ifdef ACE_GETACL
|
||
|
+ /* Solaris also has a different variant of ACLs, used in ZFS and NFSv4
|
||
|
+ file systems (whereas the other ones are used in UFS file systems).
|
||
|
+ There is an API
|
||
|
+ pathconf (name, _PC_ACL_ENABLED)
|
||
|
+ fpathconf (desc, _PC_ACL_ENABLED)
|
||
|
+ that allows to determine which of the two kinds of ACLs is supported
|
||
|
+ for the given file. But some file systems may implement this call
|
||
|
+ incorrectly, so better not use it.
|
||
|
+ When fetching the source ACL, we simply fetch both ACL types.
|
||
|
+ When setting the destination ACL, we try either ACL types, assuming
|
||
|
+ that the kernel will translate the ACL from one form to the other.
|
||
|
+ (See in <http://docs.sun.com/app/docs/doc/819-2241/6n4huc7ia?l=en&a=view>
|
||
|
+ the description of ENOTSUP.) */
|
||
|
+ for (;;)
|
||
|
+ {
|
||
|
+ ace_count = (source_desc != -1
|
||
|
+ ? facl (source_desc, ACE_GETACLCNT, 0, NULL)
|
||
|
+ : acl (src_name, ACE_GETACLCNT, 0, NULL));
|
||
|
+
|
||
|
+ if (ace_count < 0)
|
||
|
+ {
|
||
|
+ if (errno == ENOSYS || errno == EINVAL)
|
||
|
+ {
|
||
|
+ ace_count = 0;
|
||
|
+ ace_entries = NULL;
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ else
|
||
|
+ return -2;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (ace_count == 0)
|
||
|
+ {
|
||
|
+ ace_entries = NULL;
|
||
|
+ break;
|
||
|
+ }
|
||
|
+
|
||
|
+ ace_entries = (ace_t *) malloc (ace_count * sizeof (ace_t));
|
||
|
+ if (ace_entries == NULL)
|
||
|
+ {
|
||
|
+ errno = ENOMEM;
|
||
|
+ return -2;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = (source_desc != -1
|
||
|
+ ? facl (source_desc, ACE_GETACL, ace_count, ace_entries)
|
||
|
+ : acl (src_name, ACE_GETACL, ace_count, ace_entries));
|
||
|
+ if (ret < 0)
|
||
|
+ {
|
||
|
+ free (ace_entries);
|
||
|
+ if (errno == ENOSYS || errno == EINVAL)
|
||
|
+ {
|
||
|
+ ace_count = 0;
|
||
|
+ ace_entries = NULL;
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ else
|
||
|
+ return -2;
|
||
|
+ }
|
||
|
+ if (ret == ace_count)
|
||
|
+ break;
|
||
|
+ /* Huh? The number of ACL entries changed since the last call.
|
||
|
+ Repeat. */
|
||
|
+ }
|
||
|
+# endif
|
||
|
+
|
||
|
+ for (;;)
|
||
|
+ {
|
||
|
+ count = (source_desc != -1
|
||
|
+ ? facl (source_desc, GETACLCNT, 0, NULL)
|
||
|
+ : acl (src_name, GETACLCNT, 0, NULL));
|
||
|
+
|
||
|
+ if (count < 0)
|
||
|
+ {
|
||
|
+ if (errno == ENOSYS || errno == ENOTSUP || errno == EOPNOTSUPP)
|
||
|
+ {
|
||
|
+ count = 0;
|
||
|
+ entries = NULL;
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ else
|
||
|
+ return -2;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (count == 0)
|
||
|
+ {
|
||
|
+ entries = NULL;
|
||
|
+ break;
|
||
|
+ }
|
||
|
+
|
||
|
+ entries = (aclent_t *) malloc (count * sizeof (aclent_t));
|
||
|
+ if (entries == NULL)
|
||
|
+ {
|
||
|
+ errno = ENOMEM;
|
||
|
+ return -2;
|
||
|
+ }
|
||
|
+
|
||
|
+ if ((source_desc != -1
|
||
|
+ ? facl (source_desc, GETACL, count, entries)
|
||
|
+ : acl (src_name, GETACL, count, entries))
|
||
|
+ == count)
|
||
|
+ break;
|
||
|
+ /* Huh? The number of ACL entries changed since the last call.
|
||
|
+ Repeat. */
|
||
|
+ }
|
||
|
+
|
||
|
+ /* Is there an ACL of either kind? */
|
||
|
+# ifdef ACE_GETACL
|
||
|
+ if (ace_count == 0)
|
||
|
+# endif
|
||
|
+ if (count == 0)
|
||
|
+ return qset_acl (dst_name, dest_desc, mode);
|
||
|
+
|
||
|
+ did_chmod = 0; /* set to 1 once the mode bits in 0777 have been set */
|
||
|
+ saved_errno = 0; /* the first non-ignorable error code */
|
||
|
+
|
||
|
+ if (!MODE_INSIDE_ACL)
|
||
|
+ {
|
||
|
+ /* On Cygwin, it is necessary to call chmod before acl, because
|
||
|
+ chmod can change the contents of the ACL (in ways that don't
|
||
|
+ change the allowed accesses, but still visible). */
|
||
|
+ if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
|
||
|
+ saved_errno = errno;
|
||
|
+ did_chmod = 1;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* If both ace_entries and entries are available, try SETACL before
|
||
|
+ ACE_SETACL, because SETACL cannot fail with ENOTSUP whereas ACE_SETACL
|
||
|
+ can. */
|
||
|
+
|
||
|
+ if (count > 0)
|
||
|
+ {
|
||
|
+ ret = (dest_desc != -1
|
||
|
+ ? facl (dest_desc, SETACL, count, entries)
|
||
|
+ : acl (dst_name, SETACL, count, entries));
|
||
|
+ if (ret < 0 && saved_errno == 0)
|
||
|
+ {
|
||
|
+ saved_errno = errno;
|
||
|
+ if ((errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
|
||
|
+ && !acl_nontrivial (count, entries))
|
||
|
+ saved_errno = 0;
|
||
|
+ }
|
||
|
+ else
|
||
|
+ did_chmod = 1;
|
||
|
+ }
|
||
|
+ free (entries);
|
||
|
+
|
||
|
+# ifdef ACE_GETACL
|
||
|
+ if (ace_count > 0)
|
||
|
+ {
|
||
|
+ ret = (dest_desc != -1
|
||
|
+ ? facl (dest_desc, ACE_SETACL, ace_count, ace_entries)
|
||
|
+ : acl (dst_name, ACE_SETACL, ace_count, ace_entries));
|
||
|
+ if (ret < 0 && saved_errno == 0)
|
||
|
+ {
|
||
|
+ saved_errno = errno;
|
||
|
+ if ((errno == ENOSYS || errno == EINVAL || errno == ENOTSUP)
|
||
|
+ && !acl_ace_nontrivial (ace_count, ace_entries))
|
||
|
+ saved_errno = 0;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ free (ace_entries);
|
||
|
+# endif
|
||
|
+
|
||
|
+ if (MODE_INSIDE_ACL
|
||
|
+ && did_chmod <= ((mode & (S_ISUID | S_ISGID | S_ISVTX)) ? 1 : 0))
|
||
|
+ {
|
||
|
+ /* 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. */
|
||
|
+
|
||
|
+ if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
|
||
|
+ {
|
||
|
+ if (saved_errno == 0)
|
||
|
+ saved_errno = errno;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ if (saved_errno)
|
||
|
+ {
|
||
|
+ errno = saved_errno;
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+ return 0;
|
||
|
+
|
||
|
+#elif USE_ACL && HAVE_GETACL /* HP-UX */
|
||
|
+
|
||
|
+ struct acl_entry entries[NACLENTRIES];
|
||
|
+ int count;
|
||
|
+# if HAVE_ACLV_H
|
||
|
+ struct acl aclv_entries[NACLVENTRIES];
|
||
|
+ int aclv_count;
|
||
|
+# endif
|
||
|
+ int did_chmod;
|
||
|
+ int saved_errno;
|
||
|
+ int ret;
|
||
|
+
|
||
|
+ count = (source_desc != -1
|
||
|
+ ? fgetacl (source_desc, NACLENTRIES, entries)
|
||
|
+ : getacl (src_name, NACLENTRIES, entries));
|
||
|
+
|
||
|
+ if (count < 0)
|
||
|
+ {
|
||
|
+ if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP)
|
||
|
+ count = 0;
|
||
|
+ else
|
||
|
+ return -2;
|
||
|
+ }
|
||
|
+ else if (count > 0)
|
||
|
+ {
|
||
|
+ if (count > NACLENTRIES)
|
||
|
+ /* If NACLENTRIES cannot be trusted, use dynamic memory allocation. */
|
||
|
+ abort ();
|
||
|
+ }
|
||
|
+
|
||
|
+# if HAVE_ACLV_H
|
||
|
+ aclv_count = acl ((char *) src_name, ACL_GET, NACLVENTRIES, aclv_entries);
|
||
|
+
|
||
|
+ if (aclv_count < 0)
|
||
|
+ {
|
||
|
+ if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
|
||
|
+ count = 0;
|
||
|
+ else
|
||
|
+ return -2;
|
||
|
+ }
|
||
|
+ else if (aclv_count > 0)
|
||
|
+ {
|
||
|
+ if (aclv_count > NACLVENTRIES)
|
||
|
+ /* If NACLVENTRIES cannot be trusted, use dynamic memory allocation. */
|
||
|
+ abort ();
|
||
|
+ }
|
||
|
+# endif
|
||
|
+
|
||
|
+ if (count == 0)
|
||
|
+# if HAVE_ACLV_H
|
||
|
+ if (aclv_count == 0)
|
||
|
+# endif
|
||
|
+ return qset_acl (dst_name, dest_desc, mode);
|
||
|
+
|
||
|
+ did_chmod = 0; /* set to 1 once the mode bits in 0777 have been set */
|
||
|
+ saved_errno = 0; /* the first non-ignorable error code */
|
||
|
+
|
||
|
+ if (count > 0)
|
||
|
+ {
|
||
|
+ ret = (dest_desc != -1
|
||
|
+ ? fsetacl (dest_desc, count, entries)
|
||
|
+ : setacl (dst_name, count, entries));
|
||
|
+ if (ret < 0 && saved_errno == 0)
|
||
|
+ {
|
||
|
+ saved_errno = errno;
|
||
|
+ if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP)
|
||
|
+ {
|
||
|
+ struct stat source_statbuf;
|
||
|
+
|
||
|
+ if ((source_desc != -1
|
||
|
+ ? fstat (source_desc, &source_statbuf)
|
||
|
+ : stat (src_name, &source_statbuf)) == 0)
|
||
|
+ {
|
||
|
+ if (!acl_nontrivial (count, entries, &source_statbuf))
|
||
|
+ saved_errno = 0;
|
||
|
+ }
|
||
|
+ else
|
||
|
+ saved_errno = errno;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ else
|
||
|
+ did_chmod = 1;
|
||
|
+ }
|
||
|
+
|
||
|
+# if HAVE_ACLV_H
|
||
|
+ if (aclv_count > 0)
|
||
|
+ {
|
||
|
+ ret = acl ((char *) dst_name, ACL_SET, aclv_count, aclv_entries);
|
||
|
+ if (ret < 0 && saved_errno == 0)
|
||
|
+ {
|
||
|
+ saved_errno = errno;
|
||
|
+ if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
|
||
|
+ {
|
||
|
+ if (!aclv_nontrivial (aclv_count, aclv_entries))
|
||
|
+ saved_errno = 0;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ else
|
||
|
+ did_chmod = 1;
|
||
|
+ }
|
||
|
+# endif
|
||
|
+
|
||
|
+ if (did_chmod <= ((mode & (S_ISUID | S_ISGID | S_ISVTX)) ? 1 : 0))
|
||
|
+ {
|
||
|
+ /* We did not call chmod so far, and special bits are to be set which
|
||
|
+ don't fit into ACLs. */
|
||
|
+
|
||
|
+ if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
|
||
|
+ {
|
||
|
+ if (saved_errno == 0)
|
||
|
+ saved_errno = errno;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ if (saved_errno)
|
||
|
+ {
|
||
|
+ errno = saved_errno;
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+ return 0;
|
||
|
+
|
||
|
+#elif USE_ACL && HAVE_ACLX_GET && 0 /* AIX */
|
||
|
+
|
||
|
+ /* TODO */
|
||
|
+
|
||
|
+#elif USE_ACL && HAVE_STATACL /* older AIX */
|
||
|
+
|
||
|
+ union { struct acl a; char room[4096]; } u;
|
||
|
+ int ret;
|
||
|
+
|
||
|
+ if ((source_desc != -1
|
||
|
+ ? fstatacl (source_desc, STX_NORMAL, &u.a, sizeof (u))
|
||
|
+ : statacl (src_name, STX_NORMAL, &u.a, sizeof (u)))
|
||
|
+ < 0)
|
||
|
+ return -2;
|
||
|
+
|
||
|
+ ret = (dest_desc != -1
|
||
|
+ ? fchacl (dest_desc, &u.a, u.a.acl_len)
|
||
|
+ : chacl (dst_name, &u.a, u.a.acl_len));
|
||
|
+ if (ret < 0)
|
||
|
+ {
|
||
|
+ int saved_errno = errno;
|
||
|
+
|
||
|
+ chmod_or_fchmod (dst_name, dest_desc, mode);
|
||
|
+ errno = saved_errno;
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* No need to call chmod_or_fchmod at this point, since the mode bits
|
||
|
+ S_ISUID, S_ISGID, S_ISVTX are also stored in the ACL. */
|
||
|
+
|
||
|
+ return 0;
|
||
|
+
|
||
|
+#elif USE_ACL && HAVE_ACLSORT /* NonStop Kernel */
|
||
|
+
|
||
|
+ struct acl entries[NACLENTRIES];
|
||
|
+ int count;
|
||
|
+ int ret;
|
||
|
+
|
||
|
+ count = acl ((char *) src_name, ACL_GET, NACLENTRIES, entries);
|
||
|
+
|
||
|
+ if (count < 0)
|
||
|
+ {
|
||
|
+ if (0)
|
||
|
+ count = 0;
|
||
|
+ else
|
||
|
+ return -2;
|
||
|
+ }
|
||
|
+ else if (count > 0)
|
||
|
+ {
|
||
|
+ if (count > NACLENTRIES)
|
||
|
+ /* If NACLENTRIES cannot be trusted, use dynamic memory allocation. */
|
||
|
+ abort ();
|
||
|
+ }
|
||
|
+
|
||
|
+ 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);
|
||
|
+
|
||
|
+#endif
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
+/* Copy access control lists from one file to another. If SOURCE_DESC is
|
||
|
+ a valid file descriptor, use file descriptor operations, else use
|
||
|
+ filename based operations on SRC_NAME. Likewise for DEST_DESC and
|
||
|
+ DST_NAME.
|
||
|
+ If access control lists are not available, fchmod the target file to
|
||
|
+ MODE. Also sets the non-permission bits of the destination file
|
||
|
+ (S_ISUID, S_ISGID, S_ISVTX) to those from MODE if any are set.
|
||
|
+ Return 0 if successful, otherwise output a diagnostic and return a
|
||
|
+ negative error code. */
|
||
|
+
|
||
|
+int
|
||
|
+copy_acl (const char *src_name, int source_desc, const char *dst_name,
|
||
|
+ int dest_desc, mode_t mode)
|
||
|
+{
|
||
|
+ int ret = qcopy_acl (src_name, source_desc, dst_name, dest_desc, mode);
|
||
|
+ switch (ret)
|
||
|
+ {
|
||
|
+ case -2:
|
||
|
+ error (0, errno, "%s", quote (src_name));
|
||
|
+ break;
|
||
|
+
|
||
|
+ case -1:
|
||
|
+ error (0, errno, _("preserving permissions for %s"), quote (dst_name));
|
||
|
+ break;
|
||
|
+
|
||
|
+ default:
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ return ret;
|
||
|
+}
|
||
|
diff --git a/gnu/file-has-acl.c b/gnu/file-has-acl.c
|
||
|
new file mode 100644
|
||
|
index 0000000..17872a5
|
||
|
--- /dev/null
|
||
|
+++ b/gnu/file-has-acl.c
|
||
|
@@ -0,0 +1,920 @@
|
||
|
+/* -*- buffer-read-only: t -*- vi: set ro: */
|
||
|
+/* DO NOT EDIT! GENERATED AUTOMATICALLY! */
|
||
|
+/* Test whether a file has a nontrivial access control list.
|
||
|
+
|
||
|
+ Copyright (C) 2002-2003, 2005-2012 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 <http://www.gnu.org/licenses/>.
|
||
|
+
|
||
|
+ Written by Paul Eggert, Andreas Grünbacher, and Bruno Haible. */
|
||
|
+
|
||
|
+/* Without this pragma, gcc 4.7.0 20120126 may suggest that the
|
||
|
+ file_has_acl function might be candidate for attribute 'const' */
|
||
|
+#if (__GNUC__ == 4 && 6 <= __GNUC_MINOR__) || 4 < __GNUC__
|
||
|
+# pragma GCC diagnostic ignored "-Wsuggest-attribute=const"
|
||
|
+#endif
|
||
|
+
|
||
|
+#include <config.h>
|
||
|
+
|
||
|
+#include "acl.h"
|
||
|
+
|
||
|
+#include "acl-internal.h"
|
||
|
+
|
||
|
+
|
||
|
+#if USE_ACL && HAVE_ACL_GET_FILE
|
||
|
+
|
||
|
+# if HAVE_ACL_TYPE_EXTENDED /* Mac OS X */
|
||
|
+
|
||
|
+/* ACL is an ACL, from a file, stored as type ACL_TYPE_EXTENDED.
|
||
|
+ Return 1 if the given ACL is non-trivial.
|
||
|
+ Return 0 if it is trivial. */
|
||
|
+int
|
||
|
+acl_extended_nontrivial (acl_t acl)
|
||
|
+{
|
||
|
+ /* acl is non-trivial if it is non-empty. */
|
||
|
+ return (acl_entries (acl) > 0);
|
||
|
+}
|
||
|
+
|
||
|
+# else /* Linux, FreeBSD, IRIX, Tru64 */
|
||
|
+
|
||
|
+/* ACL is an ACL, from a file, stored as type ACL_TYPE_ACCESS.
|
||
|
+ Return 1 if the given ACL is non-trivial.
|
||
|
+ Return 0 if it is trivial, i.e. equivalent to a simple stat() mode.
|
||
|
+ Return -1 and set errno upon failure to determine it. */
|
||
|
+int
|
||
|
+acl_access_nontrivial (acl_t acl)
|
||
|
+{
|
||
|
+ /* acl is non-trivial if it has some entries other than for "user::",
|
||
|
+ "group::", and "other::". Normally these three should be present
|
||
|
+ at least, allowing us to write
|
||
|
+ return (3 < acl_entries (acl));
|
||
|
+ but the following code is more robust. */
|
||
|
+# if HAVE_ACL_FIRST_ENTRY /* Linux, FreeBSD */
|
||
|
+
|
||
|
+ acl_entry_t ace;
|
||
|
+ int got_one;
|
||
|
+
|
||
|
+ 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)
|
||
|
+ return -1;
|
||
|
+ if (!(tag == ACL_USER_OBJ || tag == ACL_GROUP_OBJ || tag == ACL_OTHER))
|
||
|
+ return 1;
|
||
|
+ }
|
||
|
+ return got_one;
|
||
|
+
|
||
|
+# else /* IRIX, Tru64 */
|
||
|
+# if HAVE_ACL_TO_SHORT_TEXT /* IRIX */
|
||
|
+ /* Don't use acl_get_entry: it is undocumented. */
|
||
|
+
|
||
|
+ int count = acl->acl_cnt;
|
||
|
+ int i;
|
||
|
+
|
||
|
+ for (i = 0; i < count; i++)
|
||
|
+ {
|
||
|
+ acl_entry_t ace = &acl->acl_entry[i];
|
||
|
+ acl_tag_t tag = ace->ae_tag;
|
||
|
+
|
||
|
+ if (!(tag == ACL_USER_OBJ || tag == ACL_GROUP_OBJ
|
||
|
+ || tag == ACL_OTHER_OBJ))
|
||
|
+ return 1;
|
||
|
+ }
|
||
|
+ return 0;
|
||
|
+
|
||
|
+# endif
|
||
|
+# if HAVE_ACL_FREE_TEXT /* Tru64 */
|
||
|
+ /* Don't use acl_get_entry: it takes only one argument and does not work. */
|
||
|
+
|
||
|
+ int count = acl->acl_num;
|
||
|
+ acl_entry_t ace;
|
||
|
+
|
||
|
+ for (ace = acl->acl_first; count > 0; ace = ace->next, count--)
|
||
|
+ {
|
||
|
+ acl_tag_t tag;
|
||
|
+ acl_perm_t perm;
|
||
|
+
|
||
|
+ tag = ace->entry->acl_type;
|
||
|
+ if (!(tag == ACL_USER_OBJ || tag == ACL_GROUP_OBJ || tag == ACL_OTHER))
|
||
|
+ return 1;
|
||
|
+
|
||
|
+ perm = ace->entry->acl_perm;
|
||
|
+ /* On Tru64, perm can also contain non-standard bits such as
|
||
|
+ PERM_INSERT, PERM_DELETE, PERM_MODIFY, PERM_LOOKUP, ... */
|
||
|
+ if ((perm & ~(ACL_READ | ACL_WRITE | ACL_EXECUTE)) != 0)
|
||
|
+ return 1;
|
||
|
+ }
|
||
|
+ return 0;
|
||
|
+
|
||
|
+# endif
|
||
|
+# endif
|
||
|
+}
|
||
|
+
|
||
|
+# endif
|
||
|
+
|
||
|
+
|
||
|
+#elif USE_ACL && HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
|
||
|
+
|
||
|
+/* 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. */
|
||
|
+int
|
||
|
+acl_nontrivial (int count, aclent_t *entries)
|
||
|
+{
|
||
|
+ int i;
|
||
|
+
|
||
|
+ for (i = 0; i < count; i++)
|
||
|
+ {
|
||
|
+ aclent_t *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
|
||
|
+ || ace->a_type == GROUP_OBJ
|
||
|
+ || ace->a_type == OTHER_OBJ
|
||
|
+ /* Note: Cygwin does not return a CLASS_OBJ ("mask:") entry
|
||
|
+ sometimes. */
|
||
|
+ || ace->a_type == CLASS_OBJ))
|
||
|
+ return 1;
|
||
|
+ }
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+# ifdef ACE_GETACL
|
||
|
+
|
||
|
+/* A shortcut for a bitmask. */
|
||
|
+# define NEW_ACE_WRITEA_DATA (NEW_ACE_WRITE_DATA | NEW_ACE_APPEND_DATA)
|
||
|
+
|
||
|
+/* Test an ACL retrieved with ACE_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. */
|
||
|
+int
|
||
|
+acl_ace_nontrivial (int count, ace_t *entries)
|
||
|
+{
|
||
|
+ 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++)
|
||
|
+ if (entries[i].a_flags & (OLD_ACE_OWNER | OLD_ACE_GROUP | OLD_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 == OLD_ALLOW
|
||
|
+ && (ace->a_flags == OLD_ACE_OWNER
|
||
|
+ || ace->a_flags == OLD_ACE_GROUP
|
||
|
+ || ace->a_flags == OLD_ACE_OTHER)))
|
||
|
+ return 1;
|
||
|
+ }
|
||
|
+ else
|
||
|
+ {
|
||
|
+ /* Running on Solaris 10 (newer version) or Solaris 11. */
|
||
|
+ unsigned int access_masks[6] =
|
||
|
+ {
|
||
|
+ 0, /* owner@ deny */
|
||
|
+ 0, /* owner@ allow */
|
||
|
+ 0, /* group@ deny */
|
||
|
+ 0, /* group@ allow */
|
||
|
+ 0, /* everyone@ deny */
|
||
|
+ 0 /* everyone@ allow */
|
||
|
+ };
|
||
|
+
|
||
|
+ for (i = 0; i < count; i++)
|
||
|
+ {
|
||
|
+ ace_t *ace = &entries[i];
|
||
|
+ unsigned int index1;
|
||
|
+ unsigned int index2;
|
||
|
+
|
||
|
+ if (ace->a_type == NEW_ACE_ACCESS_ALLOWED_ACE_TYPE)
|
||
|
+ index1 = 1;
|
||
|
+ else if (ace->a_type == NEW_ACE_ACCESS_DENIED_ACE_TYPE)
|
||
|
+ index1 = 0;
|
||
|
+ else
|
||
|
+ return 1;
|
||
|
+
|
||
|
+ if (ace->a_flags == NEW_ACE_OWNER)
|
||
|
+ index2 = 0;
|
||
|
+ else if (ace->a_flags == (NEW_ACE_GROUP | NEW_ACE_IDENTIFIER_GROUP))
|
||
|
+ index2 = 2;
|
||
|
+ else if (ace->a_flags == NEW_ACE_EVERYONE)
|
||
|
+ index2 = 4;
|
||
|
+ else
|
||
|
+ return 1;
|
||
|
+
|
||
|
+ access_masks[index1 + index2] |= ace->a_access_mask;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* The same bit shouldn't be both allowed and denied. */
|
||
|
+ if (access_masks[0] & access_masks[1])
|
||
|
+ return 1;
|
||
|
+ if (access_masks[2] & access_masks[3])
|
||
|
+ return 1;
|
||
|
+ if (access_masks[4] & access_masks[5])
|
||
|
+ return 1;
|
||
|
+
|
||
|
+ /* Check minimum masks. */
|
||
|
+ if ((NEW_ACE_WRITE_NAMED_ATTRS
|
||
|
+ | NEW_ACE_WRITE_ATTRIBUTES
|
||
|
+ | NEW_ACE_WRITE_ACL
|
||
|
+ | NEW_ACE_WRITE_OWNER)
|
||
|
+ & ~ access_masks[1])
|
||
|
+ return 1;
|
||
|
+ access_masks[1] &= ~(NEW_ACE_WRITE_NAMED_ATTRS
|
||
|
+ | NEW_ACE_WRITE_ATTRIBUTES
|
||
|
+ | NEW_ACE_WRITE_ACL
|
||
|
+ | NEW_ACE_WRITE_OWNER);
|
||
|
+ if ((NEW_ACE_READ_NAMED_ATTRS
|
||
|
+ | NEW_ACE_READ_ATTRIBUTES
|
||
|
+ | NEW_ACE_READ_ACL
|
||
|
+ | NEW_ACE_SYNCHRONIZE)
|
||
|
+ & ~ access_masks[5])
|
||
|
+ return 1;
|
||
|
+ access_masks[5] &= ~(NEW_ACE_READ_NAMED_ATTRS
|
||
|
+ | NEW_ACE_READ_ATTRIBUTES
|
||
|
+ | NEW_ACE_READ_ACL
|
||
|
+ | NEW_ACE_SYNCHRONIZE);
|
||
|
+
|
||
|
+ /* Check the allowed or denied bits. */
|
||
|
+ switch ((access_masks[0] | access_masks[1])
|
||
|
+ & ~(NEW_ACE_READ_NAMED_ATTRS
|
||
|
+ | NEW_ACE_READ_ATTRIBUTES
|
||
|
+ | NEW_ACE_READ_ACL
|
||
|
+ | NEW_ACE_SYNCHRONIZE))
|
||
|
+ {
|
||
|
+ case 0:
|
||
|
+ case NEW_ACE_READ_DATA:
|
||
|
+ case NEW_ACE_WRITEA_DATA:
|
||
|
+ case NEW_ACE_READ_DATA | NEW_ACE_WRITEA_DATA:
|
||
|
+ case NEW_ACE_EXECUTE:
|
||
|
+ case NEW_ACE_READ_DATA | NEW_ACE_EXECUTE:
|
||
|
+ case NEW_ACE_WRITEA_DATA | NEW_ACE_EXECUTE:
|
||
|
+ case NEW_ACE_READ_DATA | NEW_ACE_WRITEA_DATA | NEW_ACE_EXECUTE:
|
||
|
+ break;
|
||
|
+ default:
|
||
|
+ return 1;
|
||
|
+ }
|
||
|
+ switch ((access_masks[2] | access_masks[3])
|
||
|
+ & ~(NEW_ACE_READ_NAMED_ATTRS
|
||
|
+ | NEW_ACE_READ_ATTRIBUTES
|
||
|
+ | NEW_ACE_READ_ACL
|
||
|
+ | NEW_ACE_SYNCHRONIZE))
|
||
|
+ {
|
||
|
+ case 0:
|
||
|
+ case NEW_ACE_READ_DATA:
|
||
|
+ case NEW_ACE_WRITEA_DATA:
|
||
|
+ case NEW_ACE_READ_DATA | NEW_ACE_WRITEA_DATA:
|
||
|
+ case NEW_ACE_EXECUTE:
|
||
|
+ case NEW_ACE_READ_DATA | NEW_ACE_EXECUTE:
|
||
|
+ case NEW_ACE_WRITEA_DATA | NEW_ACE_EXECUTE:
|
||
|
+ case NEW_ACE_READ_DATA | NEW_ACE_WRITEA_DATA | NEW_ACE_EXECUTE:
|
||
|
+ break;
|
||
|
+ default:
|
||
|
+ return 1;
|
||
|
+ }
|
||
|
+ switch ((access_masks[4] | access_masks[5])
|
||
|
+ & ~(NEW_ACE_WRITE_NAMED_ATTRS
|
||
|
+ | NEW_ACE_WRITE_ATTRIBUTES
|
||
|
+ | NEW_ACE_WRITE_ACL
|
||
|
+ | NEW_ACE_WRITE_OWNER))
|
||
|
+ {
|
||
|
+ case 0:
|
||
|
+ case NEW_ACE_READ_DATA:
|
||
|
+ case NEW_ACE_WRITEA_DATA:
|
||
|
+ case NEW_ACE_READ_DATA | NEW_ACE_WRITEA_DATA:
|
||
|
+ case NEW_ACE_EXECUTE:
|
||
|
+ case NEW_ACE_READ_DATA | NEW_ACE_EXECUTE:
|
||
|
+ case NEW_ACE_WRITEA_DATA | NEW_ACE_EXECUTE:
|
||
|
+ case NEW_ACE_READ_DATA | NEW_ACE_WRITEA_DATA | NEW_ACE_EXECUTE:
|
||
|
+ break;
|
||
|
+ default:
|
||
|
+ return 1;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* Check that the NEW_ACE_WRITE_DATA and NEW_ACE_APPEND_DATA bits are
|
||
|
+ either both allowed or both denied. */
|
||
|
+ if (((access_masks[0] & NEW_ACE_WRITE_DATA) != 0)
|
||
|
+ != ((access_masks[0] & NEW_ACE_APPEND_DATA) != 0))
|
||
|
+ return 1;
|
||
|
+ if (((access_masks[2] & NEW_ACE_WRITE_DATA) != 0)
|
||
|
+ != ((access_masks[2] & NEW_ACE_APPEND_DATA) != 0))
|
||
|
+ return 1;
|
||
|
+ if (((access_masks[4] & NEW_ACE_WRITE_DATA) != 0)
|
||
|
+ != ((access_masks[4] & NEW_ACE_APPEND_DATA) != 0))
|
||
|
+ return 1;
|
||
|
+ }
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+# endif
|
||
|
+
|
||
|
+#elif USE_ACL && HAVE_GETACL /* HP-UX */
|
||
|
+
|
||
|
+/* 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 (int count, struct acl_entry *entries, struct stat *sb)
|
||
|
+{
|
||
|
+ int i;
|
||
|
+
|
||
|
+ for (i = 0; i < count; i++)
|
||
|
+ {
|
||
|
+ struct acl_entry *ace = &entries[i];
|
||
|
+
|
||
|
+ if (!((ace->uid == sb->st_uid && ace->gid == ACL_NSGROUP)
|
||
|
+ || (ace->uid == ACL_NSUSER && ace->gid == sb->st_gid)
|
||
|
+ || (ace->uid == ACL_NSUSER && ace->gid == ACL_NSGROUP)))
|
||
|
+ return 1;
|
||
|
+ }
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+# if HAVE_ACLV_H /* HP-UX >= 11.11 */
|
||
|
+
|
||
|
+/* Return 1 if the given ACL is non-trivial.
|
||
|
+ Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */
|
||
|
+int
|
||
|
+aclv_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
|
||
|
+
|
||
|
+#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. */
|
||
|
+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);
|
||
|
+}
|
||
|
+
|
||
|
+# if HAVE_ACLX_GET && defined ACL_AIX_WIP /* 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
|
||
|
+
|
||
|
+#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
|
||
|
+
|
||
|
+
|
||
|
+/* 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 NAME, obtained
|
||
|
+ through stat() or lstat(). */
|
||
|
+
|
||
|
+int
|
||
|
+file_has_acl (char const *name, struct stat const *sb)
|
||
|
+{
|
||
|
+#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 */
|
||
|
+ int ret;
|
||
|
+
|
||
|
+ if (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, Mac OS X, IRIX, Tru64 */
|
||
|
+ {
|
||
|
+# if HAVE_ACL_TYPE_EXTENDED /* Mac OS X */
|
||
|
+ /* On Mac OS X, acl_get_file (name, ACL_TYPE_ACCESS)
|
||
|
+ and acl_get_file (name, ACL_TYPE_DEFAULT)
|
||
|
+ always return NULL / EINVAL. There is no point in making
|
||
|
+ these two useless calls. The real ACL is retrieved through
|
||
|
+ acl_get_file (name, ACL_TYPE_EXTENDED). */
|
||
|
+ acl_t acl = acl_get_file (name, ACL_TYPE_EXTENDED);
|
||
|
+ if (acl)
|
||
|
+ {
|
||
|
+ ret = acl_extended_nontrivial (acl);
|
||
|
+ acl_free (acl);
|
||
|
+ }
|
||
|
+ else
|
||
|
+ ret = -1;
|
||
|
+# else /* FreeBSD, IRIX, Tru64 */
|
||
|
+ acl_t acl = acl_get_file (name, ACL_TYPE_ACCESS);
|
||
|
+ if (acl)
|
||
|
+ {
|
||
|
+ int saved_errno;
|
||
|
+
|
||
|
+ ret = acl_access_nontrivial (acl);
|
||
|
+ saved_errno = errno;
|
||
|
+ acl_free (acl);
|
||
|
+ errno = saved_errno;
|
||
|
+# if HAVE_ACL_FREE_TEXT /* Tru64 */
|
||
|
+ /* 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 */
|
||
|
+ /* 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
|
||
|
+ file system. Therefore there is no point in making the second
|
||
|
+ call if the first one already failed. */
|
||
|
+ if (ret == 0 && S_ISDIR (sb->st_mode))
|
||
|
+ {
|
||
|
+ acl = acl_get_file (name, ACL_TYPE_DEFAULT);
|
||
|
+ if (acl)
|
||
|
+ {
|
||
|
+ ret = (0 < acl_entries (acl));
|
||
|
+ acl_free (acl);
|
||
|
+ }
|
||
|
+ else
|
||
|
+ ret = -1;
|
||
|
+ }
|
||
|
+# endif
|
||
|
+ }
|
||
|
+ else
|
||
|
+ ret = -1;
|
||
|
+# endif
|
||
|
+ }
|
||
|
+ if (ret < 0)
|
||
|
+ return ACL_NOT_WELL_SUPPORTED (errno) ? 0 : -1;
|
||
|
+ return ret;
|
||
|
+
|
||
|
+# elif HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
|
||
|
+
|
||
|
+# 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,
|
||
|
+ acl_fromtext, ...). */
|
||
|
+ return acl_trivial (name);
|
||
|
+
|
||
|
+# else /* Solaris, Cygwin, general case */
|
||
|
+
|
||
|
+ /* Solaris 2.5 through Solaris 10, Cygwin, and contemporaneous versions
|
||
|
+ of Unixware. The acl() call returns the access and default ACL both
|
||
|
+ at once. */
|
||
|
+ {
|
||
|
+ /* Initially, try to read the entries into a stack-allocated buffer.
|
||
|
+ Use malloc if it does not fit. */
|
||
|
+ enum
|
||
|
+ {
|
||
|
+ alloc_init = 4000 / sizeof (aclent_t), /* >= 3 */
|
||
|
+ alloc_max = MIN (INT_MAX, SIZE_MAX / sizeof (aclent_t))
|
||
|
+ };
|
||
|
+ aclent_t buf[alloc_init];
|
||
|
+ size_t alloc = alloc_init;
|
||
|
+ aclent_t *entries = buf;
|
||
|
+ aclent_t *malloced = NULL;
|
||
|
+ int count;
|
||
|
+
|
||
|
+ for (;;)
|
||
|
+ {
|
||
|
+ count = acl (name, GETACL, alloc, entries);
|
||
|
+ if (count < 0 && errno == ENOSPC)
|
||
|
+ {
|
||
|
+ /* Increase the size of the buffer. */
|
||
|
+ free (malloced);
|
||
|
+ if (alloc > alloc_max / 2)
|
||
|
+ {
|
||
|
+ errno = ENOMEM;
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+ alloc = 2 * alloc; /* <= alloc_max */
|
||
|
+ entries = malloced =
|
||
|
+ (aclent_t *) malloc (alloc * sizeof (aclent_t));
|
||
|
+ if (entries == NULL)
|
||
|
+ {
|
||
|
+ errno = ENOMEM;
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+ continue;
|
||
|
+ }
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ if (count < 0)
|
||
|
+ {
|
||
|
+ if (errno == ENOSYS || errno == ENOTSUP)
|
||
|
+ ;
|
||
|
+ else
|
||
|
+ {
|
||
|
+ int saved_errno = errno;
|
||
|
+ free (malloced);
|
||
|
+ errno = saved_errno;
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ else if (count == 0)
|
||
|
+ ;
|
||
|
+ else
|
||
|
+ {
|
||
|
+ /* Don't use MIN_ACL_ENTRIES: It's set to 4 on Cygwin, but Cygwin
|
||
|
+ 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)
|
||
|
+ {
|
||
|
+ free (malloced);
|
||
|
+ return 1;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (acl_nontrivial (count, entries))
|
||
|
+ {
|
||
|
+ free (malloced);
|
||
|
+ return 1;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ free (malloced);
|
||
|
+ }
|
||
|
+
|
||
|
+# ifdef ACE_GETACL
|
||
|
+ /* Solaris also has a different variant of ACLs, used in ZFS and NFSv4
|
||
|
+ file systems (whereas the other ones are used in UFS file systems). */
|
||
|
+ {
|
||
|
+ /* Initially, try to read the entries into a stack-allocated buffer.
|
||
|
+ Use malloc if it does not fit. */
|
||
|
+ enum
|
||
|
+ {
|
||
|
+ alloc_init = 4000 / sizeof (ace_t), /* >= 3 */
|
||
|
+ alloc_max = MIN (INT_MAX, SIZE_MAX / sizeof (ace_t))
|
||
|
+ };
|
||
|
+ ace_t buf[alloc_init];
|
||
|
+ size_t alloc = alloc_init;
|
||
|
+ ace_t *entries = buf;
|
||
|
+ ace_t *malloced = NULL;
|
||
|
+ int count;
|
||
|
+
|
||
|
+ for (;;)
|
||
|
+ {
|
||
|
+ count = acl (name, ACE_GETACL, alloc, entries);
|
||
|
+ if (count < 0 && errno == ENOSPC)
|
||
|
+ {
|
||
|
+ /* Increase the size of the buffer. */
|
||
|
+ free (malloced);
|
||
|
+ if (alloc > alloc_max / 2)
|
||
|
+ {
|
||
|
+ errno = ENOMEM;
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+ alloc = 2 * alloc; /* <= alloc_max */
|
||
|
+ entries = malloced = (ace_t *) malloc (alloc * sizeof (ace_t));
|
||
|
+ if (entries == NULL)
|
||
|
+ {
|
||
|
+ errno = ENOMEM;
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+ continue;
|
||
|
+ }
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ if (count < 0)
|
||
|
+ {
|
||
|
+ if (errno == ENOSYS || errno == EINVAL)
|
||
|
+ ;
|
||
|
+ else
|
||
|
+ {
|
||
|
+ int saved_errno = errno;
|
||
|
+ free (malloced);
|
||
|
+ errno = saved_errno;
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ else if (count == 0)
|
||
|
+ ;
|
||
|
+ else
|
||
|
+ {
|
||
|
+ /* In the old (original Solaris 10) convention:
|
||
|
+ If there are more than 3 entries, there cannot be only the
|
||
|
+ ACE_OWNER, ACE_GROUP, ACE_OTHER entries.
|
||
|
+ In the newer Solaris 10 and Solaris 11 convention:
|
||
|
+ If there are more than 6 entries, there cannot be only the
|
||
|
+ ACE_OWNER, ACE_GROUP, ACE_EVERYONE entries, each once with
|
||
|
+ NEW_ACE_ACCESS_ALLOWED_ACE_TYPE and once with
|
||
|
+ NEW_ACE_ACCESS_DENIED_ACE_TYPE. */
|
||
|
+ if (count > 6)
|
||
|
+ {
|
||
|
+ free (malloced);
|
||
|
+ return 1;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (acl_ace_nontrivial (count, entries))
|
||
|
+ {
|
||
|
+ free (malloced);
|
||
|
+ return 1;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ free (malloced);
|
||
|
+ }
|
||
|
+# endif
|
||
|
+
|
||
|
+ return 0;
|
||
|
+# endif
|
||
|
+
|
||
|
+# elif HAVE_GETACL /* HP-UX */
|
||
|
+
|
||
|
+ {
|
||
|
+ struct acl_entry entries[NACLENTRIES];
|
||
|
+ int count;
|
||
|
+
|
||
|
+ count = getacl (name, NACLENTRIES, entries);
|
||
|
+
|
||
|
+ if (count < 0)
|
||
|
+ {
|
||
|
+ /* ENOSYS is seen on newer HP-UX versions.
|
||
|
+ EOPNOTSUPP is typically seen on NFS mounts.
|
||
|
+ ENOTSUP was seen on Quantum StorNext file systems (cvfs). */
|
||
|
+ if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP)
|
||
|
+ ;
|
||
|
+ else
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+ else if (count == 0)
|
||
|
+ return 0;
|
||
|
+ else /* count > 0 */
|
||
|
+ {
|
||
|
+ if (count > NACLENTRIES)
|
||
|
+ /* If NACLENTRIES cannot be trusted, use dynamic memory
|
||
|
+ allocation. */
|
||
|
+ abort ();
|
||
|
+
|
||
|
+ /* If there are more than 3 entries, there cannot be only the
|
||
|
+ (uid,%), (%,gid), (%,%) entries. */
|
||
|
+ if (count > 3)
|
||
|
+ return 1;
|
||
|
+
|
||
|
+ {
|
||
|
+ struct stat statbuf;
|
||
|
+
|
||
|
+ if (stat (name, &statbuf) < 0)
|
||
|
+ return -1;
|
||
|
+
|
||
|
+ return acl_nontrivial (count, entries, &statbuf);
|
||
|
+ }
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+# if HAVE_ACLV_H /* HP-UX >= 11.11 */
|
||
|
+
|
||
|
+ {
|
||
|
+ struct acl entries[NACLVENTRIES];
|
||
|
+ int count;
|
||
|
+
|
||
|
+ count = acl ((char *) name, ACL_GET, NACLVENTRIES, entries);
|
||
|
+
|
||
|
+ if (count < 0)
|
||
|
+ {
|
||
|
+ /* EOPNOTSUPP is seen on NFS in HP-UX 11.11, 11.23.
|
||
|
+ EINVAL is seen on NFS in HP-UX 11.31. */
|
||
|
+ if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
|
||
|
+ ;
|
||
|
+ else
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+ else if (count == 0)
|
||
|
+ return 0;
|
||
|
+ else /* count > 0 */
|
||
|
+ {
|
||
|
+ if (count > NACLVENTRIES)
|
||
|
+ /* If NACLVENTRIES 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;
|
||
|
+
|
||
|
+ return aclv_nontrivial (count, entries);
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+# endif
|
||
|
+
|
||
|
+# elif HAVE_ACLX_GET && defined ACL_AIX_WIP /* 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 == ENOSYS)
|
||
|
+ return 0;
|
||
|
+ 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;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ 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 */
|
||
|
+
|
||
|
+ 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);
|
||
|
+
|
||
|
+# elif HAVE_ACLSORT /* NonStop Kernel */
|
||
|
+
|
||
|
+ {
|
||
|
+ struct acl entries[NACLENTRIES];
|
||
|
+ int count;
|
||
|
+
|
||
|
+ count = acl ((char *) name, ACL_GET, NACLENTRIES, entries);
|
||
|
+
|
||
|
+ if (count < 0)
|
||
|
+ {
|
||
|
+ if (errno == ENOSYS || errno == ENOTSUP)
|
||
|
+ ;
|
||
|
+ else
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+ else if (count == 0)
|
||
|
+ return 0;
|
||
|
+ else /* count > 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;
|
||
|
+
|
||
|
+ return acl_nontrivial (count, entries);
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+# endif
|
||
|
+ }
|
||
|
+#endif
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
diff --git a/gnu/getfilecon.c b/gnu/getfilecon.c
|
||
|
new file mode 100644
|
||
|
index 0000000..4a0f40d
|
||
|
--- /dev/null
|
||
|
+++ b/gnu/getfilecon.c
|
||
|
@@ -0,0 +1,88 @@
|
||
|
+/* -*- buffer-read-only: t -*- vi: set ro: */
|
||
|
+/* DO NOT EDIT! GENERATED AUTOMATICALLY! */
|
||
|
+/* wrap getfilecon, lgetfilecon, and fgetfilecon
|
||
|
+ Copyright (C) 2009-2012 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, 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 <http://www.gnu.org/licenses/>. */
|
||
|
+
|
||
|
+/* written by Jim Meyering */
|
||
|
+
|
||
|
+#include <config.h>
|
||
|
+
|
||
|
+#include <selinux/selinux.h>
|
||
|
+
|
||
|
+#include <sys/types.h>
|
||
|
+#include <errno.h>
|
||
|
+#include <string.h>
|
||
|
+
|
||
|
+/* FIXME: remove this once there is an errno-gnu module
|
||
|
+ that guarantees the definition of ENODATA. */
|
||
|
+#ifndef ENODATA
|
||
|
+# define ENODATA ENOTSUP
|
||
|
+#endif
|
||
|
+
|
||
|
+#undef getfilecon
|
||
|
+#undef lgetfilecon
|
||
|
+#undef fgetfilecon
|
||
|
+int getfilecon (char const *file, security_context_t *con);
|
||
|
+int lgetfilecon (char const *file, security_context_t *con);
|
||
|
+int fgetfilecon (int fd, security_context_t *con);
|
||
|
+
|
||
|
+/* getfilecon, lgetfilecon, and fgetfilecon can all 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. */
|
||
|
+
|
||
|
+static inline int
|
||
|
+map_to_failure (int ret, security_context_t *con)
|
||
|
+{
|
||
|
+ if (ret == 0)
|
||
|
+ {
|
||
|
+ errno = ENOTSUP;
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (ret == 10 && strcmp (*con, "unlabeled") == 0)
|
||
|
+ {
|
||
|
+ freecon (*con);
|
||
|
+ errno = ENODATA;
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
+int
|
||
|
+rpl_getfilecon (char const *file, security_context_t *con)
|
||
|
+{
|
||
|
+ int ret = getfilecon (file, con);
|
||
|
+ return map_to_failure (ret, con);
|
||
|
+}
|
||
|
+
|
||
|
+int
|
||
|
+rpl_lgetfilecon (char const *file, security_context_t *con)
|
||
|
+{
|
||
|
+ int ret = lgetfilecon (file, con);
|
||
|
+ return map_to_failure (ret, con);
|
||
|
+}
|
||
|
+
|
||
|
+int
|
||
|
+rpl_fgetfilecon (int fd, security_context_t *con)
|
||
|
+{
|
||
|
+ int ret = fgetfilecon (fd, con);
|
||
|
+ return map_to_failure (ret, con);
|
||
|
+}
|
||
|
diff --git a/gnu/se-context.in.h b/gnu/se-context.in.h
|
||
|
new file mode 100644
|
||
|
index 0000000..adb13ba
|
||
|
--- /dev/null
|
||
|
+++ b/gnu/se-context.in.h
|
||
|
@@ -0,0 +1,30 @@
|
||
|
+/* -*- buffer-read-only: t -*- vi: set ro: */
|
||
|
+/* DO NOT EDIT! GENERATED AUTOMATICALLY! */
|
||
|
+#ifndef SELINUX_CONTEXT_H
|
||
|
+# define SELINUX_CONTEXT_H
|
||
|
+
|
||
|
+# include <errno.h>
|
||
|
+
|
||
|
+/* The definition of _GL_UNUSED_PARAMETER is copied here. */
|
||
|
+
|
||
|
+typedef int context_t;
|
||
|
+static inline context_t context_new (char const *s _GL_UNUSED_PARAMETER)
|
||
|
+ { errno = ENOTSUP; return 0; }
|
||
|
+static inline char *context_str (context_t con _GL_UNUSED_PARAMETER)
|
||
|
+ { errno = ENOTSUP; return (void *) 0; }
|
||
|
+static inline void context_free (context_t c _GL_UNUSED_PARAMETER) {}
|
||
|
+
|
||
|
+static inline int context_user_set (context_t sc _GL_UNUSED_PARAMETER,
|
||
|
+ char const *s _GL_UNUSED_PARAMETER)
|
||
|
+ { errno = ENOTSUP; return -1; }
|
||
|
+static inline int context_role_set (context_t sc _GL_UNUSED_PARAMETER,
|
||
|
+ char const *s _GL_UNUSED_PARAMETER)
|
||
|
+ { errno = ENOTSUP; return -1; }
|
||
|
+static inline int context_range_set (context_t sc _GL_UNUSED_PARAMETER,
|
||
|
+ char const *s _GL_UNUSED_PARAMETER)
|
||
|
+ { errno = ENOTSUP; return -1; }
|
||
|
+static inline int context_type_set (context_t sc _GL_UNUSED_PARAMETER,
|
||
|
+ char const *s _GL_UNUSED_PARAMETER)
|
||
|
+ { errno = ENOTSUP; return -1; }
|
||
|
+
|
||
|
+#endif
|
||
|
diff --git a/gnu/se-selinux.in.h b/gnu/se-selinux.in.h
|
||
|
new file mode 100644
|
||
|
index 0000000..34205a1
|
||
|
--- /dev/null
|
||
|
+++ b/gnu/se-selinux.in.h
|
||
|
@@ -0,0 +1,99 @@
|
||
|
+/* -*- buffer-read-only: t -*- vi: set ro: */
|
||
|
+/* DO NOT EDIT! GENERATED AUTOMATICALLY! */
|
||
|
+/* Replacement <selinux/selinux.h> for platforms that lack it.
|
||
|
+ Copyright (C) 2008-2012 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 <http://www.gnu.org/licenses/>. */
|
||
|
+
|
||
|
+#ifndef _@GUARD_PREFIX@_SELINUX_SELINUX_H
|
||
|
+# define _@GUARD_PREFIX@_SELINUX_SELINUX_H
|
||
|
+
|
||
|
+# if __GNUC__ >= 3
|
||
|
+@PRAGMA_SYSTEM_HEADER@
|
||
|
+# endif
|
||
|
+@PRAGMA_COLUMNS@
|
||
|
+
|
||
|
+# if HAVE_SELINUX_SELINUX_H
|
||
|
+
|
||
|
+#@INCLUDE_NEXT@ @NEXT_SELINUX_SELINUX_H@
|
||
|
+
|
||
|
+# else
|
||
|
+
|
||
|
+# include <sys/types.h>
|
||
|
+# include <errno.h>
|
||
|
+
|
||
|
+/* The definition of _GL_UNUSED_PARAMETER is copied here. */
|
||
|
+
|
||
|
+# if !GNULIB_defined_security_types
|
||
|
+
|
||
|
+typedef unsigned short security_class_t;
|
||
|
+# define security_context_t char*
|
||
|
+# define is_selinux_enabled() 0
|
||
|
+
|
||
|
+static inline int getcon (security_context_t *con _GL_UNUSED_PARAMETER)
|
||
|
+ { errno = ENOTSUP; return -1; }
|
||
|
+static inline void freecon (security_context_t con _GL_UNUSED_PARAMETER) {}
|
||
|
+
|
||
|
+
|
||
|
+static inline int getfscreatecon (security_context_t *con _GL_UNUSED_PARAMETER)
|
||
|
+ { errno = ENOTSUP; return -1; }
|
||
|
+static inline int setfscreatecon (security_context_t con _GL_UNUSED_PARAMETER)
|
||
|
+ { errno = ENOTSUP; return -1; }
|
||
|
+static inline int matchpathcon (char const *file _GL_UNUSED_PARAMETER,
|
||
|
+ mode_t m _GL_UNUSED_PARAMETER,
|
||
|
+ security_context_t *con _GL_UNUSED_PARAMETER)
|
||
|
+ { errno = ENOTSUP; return -1; }
|
||
|
+static inline int getfilecon (char const *file _GL_UNUSED_PARAMETER,
|
||
|
+ security_context_t *con _GL_UNUSED_PARAMETER)
|
||
|
+ { errno = ENOTSUP; return -1; }
|
||
|
+static inline int lgetfilecon (char const *file _GL_UNUSED_PARAMETER,
|
||
|
+ security_context_t *con _GL_UNUSED_PARAMETER)
|
||
|
+ { errno = ENOTSUP; return -1; }
|
||
|
+static inline int fgetfilecon (int fd,
|
||
|
+ security_context_t *con _GL_UNUSED_PARAMETER)
|
||
|
+ { errno = ENOTSUP; return -1; }
|
||
|
+static inline int setfilecon (char const *file _GL_UNUSED_PARAMETER,
|
||
|
+ security_context_t con _GL_UNUSED_PARAMETER)
|
||
|
+ { errno = ENOTSUP; return -1; }
|
||
|
+static inline int lsetfilecon (char const *file _GL_UNUSED_PARAMETER,
|
||
|
+ security_context_t con _GL_UNUSED_PARAMETER)
|
||
|
+ { errno = ENOTSUP; return -1; }
|
||
|
+static inline int fsetfilecon (int fd _GL_UNUSED_PARAMETER,
|
||
|
+ security_context_t con _GL_UNUSED_PARAMETER)
|
||
|
+ { errno = ENOTSUP; return -1; }
|
||
|
+
|
||
|
+static inline int security_check_context
|
||
|
+ (security_context_t con _GL_UNUSED_PARAMETER)
|
||
|
+ { errno = ENOTSUP; return -1; }
|
||
|
+static inline int security_check_context_raw
|
||
|
+ (security_context_t con _GL_UNUSED_PARAMETER)
|
||
|
+ { errno = ENOTSUP; return -1; }
|
||
|
+static inline int setexeccon (security_context_t con _GL_UNUSED_PARAMETER)
|
||
|
+ { errno = ENOTSUP; return -1; }
|
||
|
+static inline int security_compute_create
|
||
|
+ (security_context_t scon _GL_UNUSED_PARAMETER,
|
||
|
+ security_context_t tcon _GL_UNUSED_PARAMETER,
|
||
|
+ security_class_t tclass _GL_UNUSED_PARAMETER,
|
||
|
+ security_context_t *newcon _GL_UNUSED_PARAMETER)
|
||
|
+ { errno = ENOTSUP; return -1; }
|
||
|
+static inline int matchpathcon_init_prefix
|
||
|
+ (char const *path _GL_UNUSED_PARAMETER,
|
||
|
+ char const *prefix _GL_UNUSED_PARAMETER)
|
||
|
+ { errno = ENOTSUP; return -1; }
|
||
|
+
|
||
|
+# define GNULIB_defined_security_types 1
|
||
|
+# endif
|
||
|
+
|
||
|
+# endif
|
||
|
+#endif /* _@GUARD_PREFIX@_SELINUX_SELINUX_H */
|
||
|
diff --git a/gnu/selinux-at.c b/gnu/selinux-at.c
|
||
|
new file mode 100644
|
||
|
index 0000000..f6619fa
|
||
|
--- /dev/null
|
||
|
+++ b/gnu/selinux-at.c
|
||
|
@@ -0,0 +1,74 @@
|
||
|
+/* -*- buffer-read-only: t -*- vi: set ro: */
|
||
|
+/* DO NOT EDIT! GENERATED AUTOMATICALLY! */
|
||
|
+/* openat-style fd-relative functions for SE Linux
|
||
|
+ Copyright (C) 2007, 2009-2012 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 <http://www.gnu.org/licenses/>. */
|
||
|
+
|
||
|
+/* written by Jim Meyering */
|
||
|
+
|
||
|
+#include <config.h>
|
||
|
+
|
||
|
+#include "selinux-at.h"
|
||
|
+#include "openat.h"
|
||
|
+
|
||
|
+#include <stdlib.h>
|
||
|
+#include <unistd.h>
|
||
|
+#include <errno.h>
|
||
|
+#include <fcntl.h>
|
||
|
+
|
||
|
+#include "dirname.h" /* solely for definition of IS_ABSOLUTE_FILE_NAME */
|
||
|
+#include "save-cwd.h"
|
||
|
+
|
||
|
+#include "openat-priv.h"
|
||
|
+
|
||
|
+#define AT_FUNC_NAME getfileconat
|
||
|
+#define AT_FUNC_F1 getfilecon
|
||
|
+#define AT_FUNC_POST_FILE_PARAM_DECLS , security_context_t *con
|
||
|
+#define AT_FUNC_POST_FILE_ARGS , con
|
||
|
+#include "at-func.c"
|
||
|
+#undef AT_FUNC_NAME
|
||
|
+#undef AT_FUNC_F1
|
||
|
+#undef AT_FUNC_POST_FILE_PARAM_DECLS
|
||
|
+#undef AT_FUNC_POST_FILE_ARGS
|
||
|
+
|
||
|
+#define AT_FUNC_NAME lgetfileconat
|
||
|
+#define AT_FUNC_F1 lgetfilecon
|
||
|
+#define AT_FUNC_POST_FILE_PARAM_DECLS , security_context_t *con
|
||
|
+#define AT_FUNC_POST_FILE_ARGS , con
|
||
|
+#include "at-func.c"
|
||
|
+#undef AT_FUNC_NAME
|
||
|
+#undef AT_FUNC_F1
|
||
|
+#undef AT_FUNC_POST_FILE_PARAM_DECLS
|
||
|
+#undef AT_FUNC_POST_FILE_ARGS
|
||
|
+
|
||
|
+#define AT_FUNC_NAME setfileconat
|
||
|
+#define AT_FUNC_F1 setfilecon
|
||
|
+#define AT_FUNC_POST_FILE_PARAM_DECLS , security_context_t con
|
||
|
+#define AT_FUNC_POST_FILE_ARGS , con
|
||
|
+#include "at-func.c"
|
||
|
+#undef AT_FUNC_NAME
|
||
|
+#undef AT_FUNC_F1
|
||
|
+#undef AT_FUNC_POST_FILE_PARAM_DECLS
|
||
|
+#undef AT_FUNC_POST_FILE_ARGS
|
||
|
+
|
||
|
+#define AT_FUNC_NAME lsetfileconat
|
||
|
+#define AT_FUNC_F1 lsetfilecon
|
||
|
+#define AT_FUNC_POST_FILE_PARAM_DECLS , security_context_t con
|
||
|
+#define AT_FUNC_POST_FILE_ARGS , con
|
||
|
+#include "at-func.c"
|
||
|
+#undef AT_FUNC_NAME
|
||
|
+#undef AT_FUNC_F1
|
||
|
+#undef AT_FUNC_POST_FILE_PARAM_DECLS
|
||
|
+#undef AT_FUNC_POST_FILE_ARGS
|
||
|
diff --git a/gnu/selinux-at.h b/gnu/selinux-at.h
|
||
|
new file mode 100644
|
||
|
index 0000000..4ab3109
|
||
|
--- /dev/null
|
||
|
+++ b/gnu/selinux-at.h
|
||
|
@@ -0,0 +1,54 @@
|
||
|
+/* -*- buffer-read-only: t -*- vi: set ro: */
|
||
|
+/* DO NOT EDIT! GENERATED AUTOMATICALLY! */
|
||
|
+/* Prototypes for openat-style fd-relative SELinux functions
|
||
|
+ Copyright (C) 2007, 2009-2012 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 <http://www.gnu.org/licenses/>. */
|
||
|
+
|
||
|
+#include <selinux/selinux.h>
|
||
|
+#include <selinux/context.h>
|
||
|
+
|
||
|
+/* These are the dir-fd-relative variants of the functions without the
|
||
|
+ "at" suffix. For example, getfileconat (AT_FDCWD, file, &c) is usually
|
||
|
+ equivalent to getfilecon (file, &c). The emulation is accomplished
|
||
|
+ by first attempting getfilecon ("/proc/self/fd/DIR_FD/FILE", &c).
|
||
|
+ Failing that, simulate it via save_cwd/fchdir/getfilecon/restore_cwd.
|
||
|
+ If either the save_cwd or the restore_cwd fails (relatively unlikely),
|
||
|
+ then give a diagnostic and exit nonzero. */
|
||
|
+
|
||
|
+/* dir-fd-relative getfilecon. Set *CON to the SELinux security context
|
||
|
+ of the file specified by DIR_FD and FILE and return the length of *CON.
|
||
|
+ DIR_FD and FILE are interpreted as for fstatat[*]. A non-NULL *CON
|
||
|
+ must be freed with freecon. Upon error, set *CON to NULL, set errno
|
||
|
+ and return -1.
|
||
|
+ [*] with flags=0 here, with flags=AT_SYMLINK_NOFOLLOW for lgetfileconat */
|
||
|
+int getfileconat (int dir_fd, char const *file, security_context_t *con);
|
||
|
+
|
||
|
+/* dir-fd-relative lgetfilecon. This function is just like getfileconat,
|
||
|
+ except when DIR_FD and FILE specify a symlink: lgetfileconat operates on
|
||
|
+ the symlink, while getfileconat operates on the referent of the symlink. */
|
||
|
+int lgetfileconat (int dir_fd, char const *file, security_context_t *con);
|
||
|
+
|
||
|
+/* dir-fd-relative setfilecon. Set the SELinux security context of
|
||
|
+ the file specified by DIR_FD and FILE to CON. DIR_FD and FILE are
|
||
|
+ interpreted as for fstatat[*]. Upon success, return 0.
|
||
|
+ Otherwise, return -1 and set errno. */
|
||
|
+int setfileconat (int dir_fd, char const *file, security_context_t con);
|
||
|
+
|
||
|
+/* dir-fd-relative lsetfilecon. This function is just like setfileconat,
|
||
|
+ except that rather than dereferencing a symlink, this function affects it. */
|
||
|
+/* dir-fd-relative lsetfilecon. This function is just like setfileconat,
|
||
|
+ except when DIR_FD and FILE specify a symlink: lsetfileconat operates on
|
||
|
+ the symlink, while setfileconat operates on the referent of the symlink. */
|
||
|
+int lsetfileconat (int dir_fd, char const *file, security_context_t con);
|
||
|
diff --git a/gnu/set-mode-acl.c b/gnu/set-mode-acl.c
|
||
|
new file mode 100644
|
||
|
index 0000000..edc8e26
|
||
|
--- /dev/null
|
||
|
+++ b/gnu/set-mode-acl.c
|
||
|
@@ -0,0 +1,699 @@
|
||
|
+/* -*- buffer-read-only: t -*- vi: set ro: */
|
||
|
+/* DO NOT EDIT! GENERATED AUTOMATICALLY! */
|
||
|
+/* set-mode-acl.c - set access control list equivalent to a mode
|
||
|
+
|
||
|
+ Copyright (C) 2002-2003, 2005-2012 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 <http://www.gnu.org/licenses/>.
|
||
|
+
|
||
|
+ Written by Paul Eggert and Andreas Gruenbacher, and Bruno Haible. */
|
||
|
+
|
||
|
+#include <config.h>
|
||
|
+
|
||
|
+#include "acl.h"
|
||
|
+
|
||
|
+#include "acl-internal.h"
|
||
|
+
|
||
|
+#include "gettext.h"
|
||
|
+#define _(msgid) gettext (msgid)
|
||
|
+
|
||
|
+
|
||
|
+/* If DESC is a valid file descriptor use fchmod to change the
|
||
|
+ file's mode to MODE on systems that have fchown. On systems
|
||
|
+ that don't have fchown and if DESC is invalid, use chown on
|
||
|
+ NAME instead.
|
||
|
+ Return 0 if successful. Return -1 and set errno upon failure. */
|
||
|
+
|
||
|
+int
|
||
|
+chmod_or_fchmod (const char *name, int desc, mode_t mode)
|
||
|
+{
|
||
|
+ if (HAVE_FCHMOD && desc != -1)
|
||
|
+ return fchmod (desc, mode);
|
||
|
+ else
|
||
|
+ return chmod (name, mode);
|
||
|
+}
|
||
|
+
|
||
|
+/* Set the access control lists of a file. If DESC is a valid file
|
||
|
+ descriptor, use file descriptor operations where available, else use
|
||
|
+ filename based operations on NAME. If access control lists are not
|
||
|
+ available, fchmod the target file to MODE. Also sets the
|
||
|
+ non-permission bits of the destination file (S_ISUID, S_ISGID, S_ISVTX)
|
||
|
+ to those from MODE if any are set.
|
||
|
+ Return 0 if successful. Return -1 and set errno upon failure. */
|
||
|
+
|
||
|
+int
|
||
|
+qset_acl (char const *name, int desc, mode_t mode)
|
||
|
+{
|
||
|
+#if USE_ACL
|
||
|
+# if HAVE_ACL_GET_FILE
|
||
|
+ /* POSIX 1003.1e draft 17 (abandoned) specific version. */
|
||
|
+ /* Linux, FreeBSD, Mac OS X, IRIX, Tru64 */
|
||
|
+# if !HAVE_ACL_TYPE_EXTENDED
|
||
|
+ /* Linux, FreeBSD, IRIX, Tru64 */
|
||
|
+
|
||
|
+ /* We must also have acl_from_text and acl_delete_def_file.
|
||
|
+ (acl_delete_def_file could be emulated with acl_init followed
|
||
|
+ by acl_set_file, but acl_set_file with an empty acl is
|
||
|
+ unspecified.) */
|
||
|
+
|
||
|
+# ifndef HAVE_ACL_FROM_TEXT
|
||
|
+# error Must have acl_from_text (see POSIX 1003.1e draft 17).
|
||
|
+# endif
|
||
|
+# ifndef HAVE_ACL_DELETE_DEF_FILE
|
||
|
+# error Must have acl_delete_def_file (see POSIX 1003.1e draft 17).
|
||
|
+# endif
|
||
|
+
|
||
|
+ acl_t acl;
|
||
|
+ int ret;
|
||
|
+
|
||
|
+ if (HAVE_ACL_FROM_MODE) /* Linux */
|
||
|
+ {
|
||
|
+ acl = acl_from_mode (mode);
|
||
|
+ if (!acl)
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+ else /* FreeBSD, IRIX, Tru64 */
|
||
|
+ {
|
||
|
+ /* If we were to create the ACL using the functions acl_init(),
|
||
|
+ acl_create_entry(), acl_set_tag_type(), acl_set_qualifier(),
|
||
|
+ acl_get_permset(), acl_clear_perm[s](), acl_add_perm(), we
|
||
|
+ would need to create a qualifier. I don't know how to do this.
|
||
|
+ So create it using acl_from_text(). */
|
||
|
+
|
||
|
+# if HAVE_ACL_FREE_TEXT /* Tru64 */
|
||
|
+ char acl_text[] = "u::---,g::---,o::---,";
|
||
|
+# else /* FreeBSD, IRIX */
|
||
|
+ char acl_text[] = "u::---,g::---,o::---";
|
||
|
+# endif
|
||
|
+
|
||
|
+ if (mode & S_IRUSR) acl_text[ 3] = 'r';
|
||
|
+ if (mode & S_IWUSR) acl_text[ 4] = 'w';
|
||
|
+ if (mode & S_IXUSR) acl_text[ 5] = 'x';
|
||
|
+ if (mode & S_IRGRP) acl_text[10] = 'r';
|
||
|
+ if (mode & S_IWGRP) acl_text[11] = 'w';
|
||
|
+ if (mode & S_IXGRP) acl_text[12] = 'x';
|
||
|
+ if (mode & S_IROTH) acl_text[17] = 'r';
|
||
|
+ if (mode & S_IWOTH) acl_text[18] = 'w';
|
||
|
+ if (mode & S_IXOTH) acl_text[19] = 'x';
|
||
|
+
|
||
|
+ acl = acl_from_text (acl_text);
|
||
|
+ if (!acl)
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+ if (HAVE_ACL_SET_FD && desc != -1)
|
||
|
+ ret = acl_set_fd (desc, acl);
|
||
|
+ else
|
||
|
+ ret = acl_set_file (name, ACL_TYPE_ACCESS, acl);
|
||
|
+ if (ret != 0)
|
||
|
+ {
|
||
|
+ int saved_errno = errno;
|
||
|
+ acl_free (acl);
|
||
|
+
|
||
|
+ if (ACL_NOT_WELL_SUPPORTED (errno))
|
||
|
+ return chmod_or_fchmod (name, desc, mode);
|
||
|
+ else
|
||
|
+ {
|
||
|
+ errno = saved_errno;
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ else
|
||
|
+ acl_free (acl);
|
||
|
+
|
||
|
+ if (S_ISDIR (mode) && acl_delete_def_file (name))
|
||
|
+ return -1;
|
||
|
+
|
||
|
+ if (!MODE_INSIDE_ACL || (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 (name, desc, mode);
|
||
|
+ }
|
||
|
+ return 0;
|
||
|
+
|
||
|
+# else /* HAVE_ACL_TYPE_EXTENDED */
|
||
|
+ /* Mac OS X */
|
||
|
+
|
||
|
+ /* On Mac OS X, acl_get_file (name, ACL_TYPE_ACCESS)
|
||
|
+ and acl_get_file (name, ACL_TYPE_DEFAULT)
|
||
|
+ always return NULL / EINVAL. You have to use
|
||
|
+ acl_get_file (name, ACL_TYPE_EXTENDED)
|
||
|
+ or acl_get_fd (open (name, ...))
|
||
|
+ to retrieve an ACL.
|
||
|
+ On the other hand,
|
||
|
+ acl_set_file (name, ACL_TYPE_ACCESS, acl)
|
||
|
+ and acl_set_file (name, ACL_TYPE_DEFAULT, acl)
|
||
|
+ have the same effect as
|
||
|
+ acl_set_file (name, ACL_TYPE_EXTENDED, acl):
|
||
|
+ Each of these calls sets the file's ACL. */
|
||
|
+
|
||
|
+ acl_t acl;
|
||
|
+ int ret;
|
||
|
+
|
||
|
+ /* Remove the ACL if the file has ACLs. */
|
||
|
+ if (HAVE_ACL_GET_FD && desc != -1)
|
||
|
+ acl = acl_get_fd (desc);
|
||
|
+ else
|
||
|
+ acl = acl_get_file (name, ACL_TYPE_EXTENDED);
|
||
|
+ if (acl)
|
||
|
+ {
|
||
|
+ acl_free (acl);
|
||
|
+
|
||
|
+ acl = acl_init (0);
|
||
|
+ if (acl)
|
||
|
+ {
|
||
|
+ if (HAVE_ACL_SET_FD && desc != -1)
|
||
|
+ ret = acl_set_fd (desc, acl);
|
||
|
+ else
|
||
|
+ ret = acl_set_file (name, ACL_TYPE_EXTENDED, acl);
|
||
|
+ if (ret != 0)
|
||
|
+ {
|
||
|
+ int saved_errno = errno;
|
||
|
+
|
||
|
+ acl_free (acl);
|
||
|
+
|
||
|
+ if (ACL_NOT_WELL_SUPPORTED (saved_errno))
|
||
|
+ return chmod_or_fchmod (name, desc, mode);
|
||
|
+ else
|
||
|
+ {
|
||
|
+ errno = saved_errno;
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ acl_free (acl);
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ /* Since !MODE_INSIDE_ACL, we have to call chmod explicitly. */
|
||
|
+ return chmod_or_fchmod (name, desc, mode);
|
||
|
+# endif
|
||
|
+
|
||
|
+# elif HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
|
||
|
+
|
||
|
+ int done_setacl = 0;
|
||
|
+
|
||
|
+# ifdef ACE_GETACL
|
||
|
+ /* Solaris also has a different variant of ACLs, used in ZFS and NFSv4
|
||
|
+ file systems (whereas the other ones are used in UFS file systems). */
|
||
|
+
|
||
|
+ /* 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?
|
||
|
+ We fetch the existing ACL. 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 convention;
|
||
|
+
|
||
|
+ {
|
||
|
+ /* Initially, try to read the entries into a stack-allocated buffer.
|
||
|
+ Use malloc if it does not fit. */
|
||
|
+ enum
|
||
|
+ {
|
||
|
+ alloc_init = 4000 / sizeof (ace_t), /* >= 3 */
|
||
|
+ alloc_max = MIN (INT_MAX, SIZE_MAX / sizeof (ace_t))
|
||
|
+ };
|
||
|
+ ace_t buf[alloc_init];
|
||
|
+ size_t alloc = alloc_init;
|
||
|
+ ace_t *entries = buf;
|
||
|
+ ace_t *malloced = NULL;
|
||
|
+ int count;
|
||
|
+
|
||
|
+ for (;;)
|
||
|
+ {
|
||
|
+ count = (desc != -1
|
||
|
+ ? facl (desc, ACE_GETACL, alloc, entries)
|
||
|
+ : acl (name, ACE_GETACL, alloc, entries));
|
||
|
+ if (count < 0 && errno == ENOSPC)
|
||
|
+ {
|
||
|
+ /* Increase the size of the buffer. */
|
||
|
+ free (malloced);
|
||
|
+ if (alloc > alloc_max / 2)
|
||
|
+ {
|
||
|
+ errno = ENOMEM;
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+ alloc = 2 * alloc; /* <= alloc_max */
|
||
|
+ entries = malloced = (ace_t *) malloc (alloc * sizeof (ace_t));
|
||
|
+ if (entries == NULL)
|
||
|
+ {
|
||
|
+ errno = ENOMEM;
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+ continue;
|
||
|
+ }
|
||
|
+ break;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (count <= 0)
|
||
|
+ convention = -1;
|
||
|
+ else
|
||
|
+ {
|
||
|
+ int i;
|
||
|
+
|
||
|
+ convention = 0;
|
||
|
+ for (i = 0; i < count; i++)
|
||
|
+ if (entries[i].a_flags & (OLD_ACE_OWNER | OLD_ACE_GROUP | OLD_ACE_OTHER))
|
||
|
+ {
|
||
|
+ convention = 1;
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ free (malloced);
|
||
|
+ }
|
||
|
+
|
||
|
+ if (convention >= 0)
|
||
|
+ {
|
||
|
+ ace_t entries[6];
|
||
|
+ int count;
|
||
|
+ int ret;
|
||
|
+
|
||
|
+ if (convention)
|
||
|
+ {
|
||
|
+ /* Running on Solaris 10. */
|
||
|
+ entries[0].a_type = OLD_ALLOW;
|
||
|
+ entries[0].a_flags = OLD_ACE_OWNER;
|
||
|
+ entries[0].a_who = 0; /* irrelevant */
|
||
|
+ entries[0].a_access_mask = (mode >> 6) & 7;
|
||
|
+ entries[1].a_type = OLD_ALLOW;
|
||
|
+ entries[1].a_flags = OLD_ACE_GROUP;
|
||
|
+ entries[1].a_who = 0; /* irrelevant */
|
||
|
+ entries[1].a_access_mask = (mode >> 3) & 7;
|
||
|
+ entries[2].a_type = OLD_ALLOW;
|
||
|
+ entries[2].a_flags = OLD_ACE_OTHER;
|
||
|
+ entries[2].a_who = 0;
|
||
|
+ entries[2].a_access_mask = mode & 7;
|
||
|
+ count = 3;
|
||
|
+ }
|
||
|
+ else
|
||
|
+ {
|
||
|
+ /* Running on Solaris 10 (newer version) or Solaris 11.
|
||
|
+ The details here were found through "/bin/ls -lvd somefiles". */
|
||
|
+ entries[0].a_type = NEW_ACE_ACCESS_DENIED_ACE_TYPE;
|
||
|
+ entries[0].a_flags = NEW_ACE_OWNER;
|
||
|
+ entries[0].a_who = 0; /* irrelevant */
|
||
|
+ entries[0].a_access_mask = 0;
|
||
|
+ entries[1].a_type = NEW_ACE_ACCESS_ALLOWED_ACE_TYPE;
|
||
|
+ entries[1].a_flags = NEW_ACE_OWNER;
|
||
|
+ entries[1].a_who = 0; /* irrelevant */
|
||
|
+ entries[1].a_access_mask = NEW_ACE_WRITE_NAMED_ATTRS
|
||
|
+ | NEW_ACE_WRITE_ATTRIBUTES
|
||
|
+ | NEW_ACE_WRITE_ACL
|
||
|
+ | NEW_ACE_WRITE_OWNER;
|
||
|
+ if (mode & 0400)
|
||
|
+ entries[1].a_access_mask |= NEW_ACE_READ_DATA;
|
||
|
+ else
|
||
|
+ entries[0].a_access_mask |= NEW_ACE_READ_DATA;
|
||
|
+ if (mode & 0200)
|
||
|
+ entries[1].a_access_mask |= NEW_ACE_WRITE_DATA | NEW_ACE_APPEND_DATA;
|
||
|
+ else
|
||
|
+ entries[0].a_access_mask |= NEW_ACE_WRITE_DATA | NEW_ACE_APPEND_DATA;
|
||
|
+ if (mode & 0100)
|
||
|
+ entries[1].a_access_mask |= NEW_ACE_EXECUTE;
|
||
|
+ else
|
||
|
+ entries[0].a_access_mask |= NEW_ACE_EXECUTE;
|
||
|
+ entries[2].a_type = NEW_ACE_ACCESS_DENIED_ACE_TYPE;
|
||
|
+ entries[2].a_flags = NEW_ACE_GROUP | NEW_ACE_IDENTIFIER_GROUP;
|
||
|
+ entries[2].a_who = 0; /* irrelevant */
|
||
|
+ entries[2].a_access_mask = 0;
|
||
|
+ entries[3].a_type = NEW_ACE_ACCESS_ALLOWED_ACE_TYPE;
|
||
|
+ entries[3].a_flags = NEW_ACE_GROUP | NEW_ACE_IDENTIFIER_GROUP;
|
||
|
+ entries[3].a_who = 0; /* irrelevant */
|
||
|
+ entries[3].a_access_mask = 0;
|
||
|
+ if (mode & 0040)
|
||
|
+ entries[3].a_access_mask |= NEW_ACE_READ_DATA;
|
||
|
+ else
|
||
|
+ entries[2].a_access_mask |= NEW_ACE_READ_DATA;
|
||
|
+ if (mode & 0020)
|
||
|
+ entries[3].a_access_mask |= NEW_ACE_WRITE_DATA | NEW_ACE_APPEND_DATA;
|
||
|
+ else
|
||
|
+ entries[2].a_access_mask |= NEW_ACE_WRITE_DATA | NEW_ACE_APPEND_DATA;
|
||
|
+ if (mode & 0010)
|
||
|
+ entries[3].a_access_mask |= NEW_ACE_EXECUTE;
|
||
|
+ else
|
||
|
+ entries[2].a_access_mask |= NEW_ACE_EXECUTE;
|
||
|
+ entries[4].a_type = NEW_ACE_ACCESS_DENIED_ACE_TYPE;
|
||
|
+ entries[4].a_flags = NEW_ACE_EVERYONE;
|
||
|
+ entries[4].a_who = 0;
|
||
|
+ entries[4].a_access_mask = NEW_ACE_WRITE_NAMED_ATTRS
|
||
|
+ | NEW_ACE_WRITE_ATTRIBUTES
|
||
|
+ | NEW_ACE_WRITE_ACL
|
||
|
+ | NEW_ACE_WRITE_OWNER;
|
||
|
+ entries[5].a_type = NEW_ACE_ACCESS_ALLOWED_ACE_TYPE;
|
||
|
+ entries[5].a_flags = NEW_ACE_EVERYONE;
|
||
|
+ entries[5].a_who = 0;
|
||
|
+ entries[5].a_access_mask = NEW_ACE_READ_NAMED_ATTRS
|
||
|
+ | NEW_ACE_READ_ATTRIBUTES
|
||
|
+ | NEW_ACE_READ_ACL
|
||
|
+ | NEW_ACE_SYNCHRONIZE;
|
||
|
+ if (mode & 0004)
|
||
|
+ entries[5].a_access_mask |= NEW_ACE_READ_DATA;
|
||
|
+ else
|
||
|
+ entries[4].a_access_mask |= NEW_ACE_READ_DATA;
|
||
|
+ if (mode & 0002)
|
||
|
+ entries[5].a_access_mask |= NEW_ACE_WRITE_DATA | NEW_ACE_APPEND_DATA;
|
||
|
+ else
|
||
|
+ entries[4].a_access_mask |= NEW_ACE_WRITE_DATA | NEW_ACE_APPEND_DATA;
|
||
|
+ if (mode & 0001)
|
||
|
+ entries[5].a_access_mask |= NEW_ACE_EXECUTE;
|
||
|
+ else
|
||
|
+ entries[4].a_access_mask |= NEW_ACE_EXECUTE;
|
||
|
+ count = 6;
|
||
|
+ }
|
||
|
+ if (desc != -1)
|
||
|
+ ret = facl (desc, ACE_SETACL, count, entries);
|
||
|
+ else
|
||
|
+ ret = acl (name, ACE_SETACL, count, entries);
|
||
|
+ if (ret < 0 && errno != EINVAL && errno != ENOTSUP)
|
||
|
+ {
|
||
|
+ if (errno == ENOSYS)
|
||
|
+ return chmod_or_fchmod (name, desc, mode);
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+ if (ret == 0)
|
||
|
+ done_setacl = 1;
|
||
|
+ }
|
||
|
+# endif
|
||
|
+
|
||
|
+ if (!done_setacl)
|
||
|
+ {
|
||
|
+ aclent_t entries[3];
|
||
|
+ 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 = OTHER_OBJ;
|
||
|
+ entries[2].a_id = 0;
|
||
|
+ entries[2].a_perm = mode & 7;
|
||
|
+
|
||
|
+ if (desc != -1)
|
||
|
+ ret = facl (desc, SETACL,
|
||
|
+ sizeof (entries) / sizeof (aclent_t), entries);
|
||
|
+ else
|
||
|
+ ret = acl (name, SETACL,
|
||
|
+ sizeof (entries) / sizeof (aclent_t), entries);
|
||
|
+ if (ret < 0)
|
||
|
+ {
|
||
|
+ if (errno == ENOSYS || errno == EOPNOTSUPP)
|
||
|
+ return chmod_or_fchmod (name, desc, mode);
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ if (!MODE_INSIDE_ACL || (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;
|
||
|
+
|
||
|
+# elif HAVE_GETACL /* HP-UX */
|
||
|
+
|
||
|
+ struct stat statbuf;
|
||
|
+ int ret;
|
||
|
+
|
||
|
+ if (desc != -1)
|
||
|
+ ret = fstat (desc, &statbuf);
|
||
|
+ else
|
||
|
+ ret = stat (name, &statbuf);
|
||
|
+ if (ret < 0)
|
||
|
+ return -1;
|
||
|
+
|
||
|
+ {
|
||
|
+ struct acl_entry entries[3];
|
||
|
+
|
||
|
+ entries[0].uid = statbuf.st_uid;
|
||
|
+ entries[0].gid = ACL_NSGROUP;
|
||
|
+ entries[0].mode = (mode >> 6) & 7;
|
||
|
+ entries[1].uid = ACL_NSUSER;
|
||
|
+ entries[1].gid = statbuf.st_gid;
|
||
|
+ entries[1].mode = (mode >> 3) & 7;
|
||
|
+ entries[2].uid = ACL_NSUSER;
|
||
|
+ entries[2].gid = ACL_NSGROUP;
|
||
|
+ entries[2].mode = mode & 7;
|
||
|
+
|
||
|
+ if (desc != -1)
|
||
|
+ ret = fsetacl (desc, sizeof (entries) / sizeof (struct acl_entry), entries);
|
||
|
+ else
|
||
|
+ ret = setacl (name, sizeof (entries) / sizeof (struct acl_entry), entries);
|
||
|
+ }
|
||
|
+ if (ret < 0)
|
||
|
+ {
|
||
|
+ if (!(errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP))
|
||
|
+ return -1;
|
||
|
+
|
||
|
+# if HAVE_ACLV_H /* HP-UX >= 11.11 */
|
||
|
+ {
|
||
|
+ struct acl entries[4];
|
||
|
+
|
||
|
+ 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 (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)
|
||
|
+ return chmod_or_fchmod (name, desc, mode);
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+ }
|
||
|
+# else
|
||
|
+ return chmod_or_fchmod (name, desc, mode);
|
||
|
+# endif
|
||
|
+ }
|
||
|
+
|
||
|
+ 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;
|
||
|
+
|
||
|
+# elif HAVE_ACLX_GET && defined ACL_AIX_WIP /* AIX */
|
||
|
+
|
||
|
+ 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;
|
||
|
+ 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 = fchacl (desc, &u.a, u.a.acl_len);
|
||
|
+ else
|
||
|
+ ret = chacl (name, &u.a, u.a.acl_len);
|
||
|
+
|
||
|
+ if (ret < 0 && errno == ENOSYS)
|
||
|
+ return chmod_or_fchmod (name, desc, 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
|
||
|
+#else /* !USE_ACL */
|
||
|
+ return chmod_or_fchmod (name, desc, mode);
|
||
|
+#endif
|
||
|
+}
|
||
|
+
|
||
|
+/* As with qset_acl, but also output a diagnostic on failure. */
|
||
|
+
|
||
|
+int
|
||
|
+set_acl (char const *name, int desc, mode_t mode)
|
||
|
+{
|
||
|
+ int ret = qset_acl (name, desc, mode);
|
||
|
+ if (ret != 0)
|
||
|
+ error (0, errno, _("setting permissions for %s"), quote (name));
|
||
|
+ return ret;
|
||
|
+}
|
||
|
diff --git a/m4/acl.m4 b/m4/acl.m4
|
||
|
new file mode 100644
|
||
|
index 0000000..19aa548
|
||
|
--- /dev/null
|
||
|
+++ b/m4/acl.m4
|
||
|
@@ -0,0 +1,165 @@
|
||
|
+# acl.m4 - check for access control list (ACL) primitives
|
||
|
+# serial 14
|
||
|
+
|
||
|
+# Copyright (C) 2002, 2004-2012 Free Software Foundation, Inc.
|
||
|
+# This file is free software; the Free Software Foundation
|
||
|
+# gives unlimited permission to copy and/or distribute it,
|
||
|
+# with or without modifications, as long as this notice is preserved.
|
||
|
+
|
||
|
+# Written by Paul Eggert and Jim Meyering.
|
||
|
+
|
||
|
+AC_DEFUN([gl_FUNC_ACL],
|
||
|
+[
|
||
|
+ AC_ARG_ENABLE([acl],
|
||
|
+ AS_HELP_STRING([--disable-acl], [do not support ACLs]),
|
||
|
+ , [enable_acl=auto])
|
||
|
+
|
||
|
+ LIB_ACL=
|
||
|
+ use_acl=0
|
||
|
+ AC_REQUIRE([AC_C_INLINE])
|
||
|
+ if test "x$enable_acl" != "xno"; then
|
||
|
+ dnl On all platforms, the ACL related API is declared in <sys/acl.h>.
|
||
|
+ AC_CHECK_HEADERS([sys/acl.h])
|
||
|
+ if test $ac_cv_header_sys_acl_h = yes; then
|
||
|
+ ac_save_LIBS=$LIBS
|
||
|
+
|
||
|
+ dnl Test for POSIX-draft-like API (Linux, FreeBSD, Mac OS X, IRIX, Tru64).
|
||
|
+ dnl -lacl is needed on Linux, -lpacl is needed on OSF/1.
|
||
|
+ if test $use_acl = 0; then
|
||
|
+ AC_SEARCH_LIBS([acl_get_file], [acl pacl],
|
||
|
+ [if test "$ac_cv_search_acl_get_file" != "none required"; then
|
||
|
+ LIB_ACL=$ac_cv_search_acl_get_file
|
||
|
+ fi
|
||
|
+ AC_CHECK_FUNCS(
|
||
|
+ [acl_get_file acl_get_fd acl_set_file acl_set_fd \
|
||
|
+ acl_free acl_from_mode acl_from_text \
|
||
|
+ 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])
|
||
|
+ # 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
|
||
|
+ dnl On Linux, additional API is declared in <acl/libacl.h>.
|
||
|
+ AC_CHECK_HEADERS([acl/libacl.h])
|
||
|
+ AC_REPLACE_FUNCS([acl_entries])
|
||
|
+ AC_CACHE_CHECK([for ACL_FIRST_ENTRY],
|
||
|
+ [gl_cv_acl_ACL_FIRST_ENTRY],
|
||
|
+ [AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
|
||
|
+[[#include <sys/types.h>
|
||
|
+#include <sys/acl.h>
|
||
|
+int type = ACL_FIRST_ENTRY;]])],
|
||
|
+ [gl_cv_acl_ACL_FIRST_ENTRY=yes],
|
||
|
+ [gl_cv_acl_ACL_FIRST_ENTRY=no])])
|
||
|
+ if test $gl_cv_acl_ACL_FIRST_ENTRY = yes; then
|
||
|
+ AC_DEFINE([HAVE_ACL_FIRST_ENTRY], [1],
|
||
|
+ [Define to 1 if the constant ACL_FIRST_ENTRY exists.])
|
||
|
+ fi
|
||
|
+ dnl On Mac OS X, other types of ACLs are supported.
|
||
|
+ AC_CACHE_CHECK([for ACL_TYPE_EXTENDED],
|
||
|
+ [gl_cv_acl_ACL_TYPE_EXTENDED],
|
||
|
+ [AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
|
||
|
+[[#include <sys/types.h>
|
||
|
+#include <sys/acl.h>
|
||
|
+int type = ACL_TYPE_EXTENDED;]])],
|
||
|
+ [gl_cv_acl_ACL_TYPE_EXTENDED=yes],
|
||
|
+ [gl_cv_acl_ACL_TYPE_EXTENDED=no])])
|
||
|
+ if test $gl_cv_acl_ACL_TYPE_EXTENDED = yes; then
|
||
|
+ AC_DEFINE([HAVE_ACL_TYPE_EXTENDED], [1],
|
||
|
+ [Define to 1 if the ACL type ACL_TYPE_EXTENDED exists.])
|
||
|
+ fi
|
||
|
+ else
|
||
|
+ LIB_ACL=
|
||
|
+ fi
|
||
|
+ ])
|
||
|
+ fi
|
||
|
+
|
||
|
+ dnl Test for Solaris API (Solaris, Cygwin).
|
||
|
+ if test $use_acl = 0; 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
|
||
|
+ fi
|
||
|
+ ])
|
||
|
+ AC_CHECK_FUNCS([acl_trivial])
|
||
|
+ use_acl=1
|
||
|
+ fi
|
||
|
+ fi
|
||
|
+
|
||
|
+ dnl Test for HP-UX API.
|
||
|
+ if test $use_acl = 0; then
|
||
|
+ AC_CHECK_FUNCS([getacl])
|
||
|
+ if test $ac_cv_func_getacl = yes; then
|
||
|
+ use_acl=1
|
||
|
+ fi
|
||
|
+ dnl Test for HP-UX 11.11 API.
|
||
|
+ AC_CHECK_HEADERS([aclv.h], [], [], [#include <sys/types.h>])
|
||
|
+ fi
|
||
|
+
|
||
|
+ dnl Test for AIX API (AIX 5.3 or newer).
|
||
|
+ if test $use_acl = 0; then
|
||
|
+ AC_CHECK_FUNCS([aclx_get])
|
||
|
+ if test $ac_cv_func_aclx_get = yes; then
|
||
|
+ use_acl=1
|
||
|
+ fi
|
||
|
+ fi
|
||
|
+
|
||
|
+ dnl Test for older AIX API.
|
||
|
+ if test $use_acl = 0 || test "$ac_cv_func_aclx_get" = yes; then
|
||
|
+ AC_CHECK_FUNCS([statacl])
|
||
|
+ if test $ac_cv_func_statacl = yes; then
|
||
|
+ use_acl=1
|
||
|
+ 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
|
||
|
+ AC_MSG_ERROR([ACLs enabled but support not detected])
|
||
|
+ elif test "x$enable_acl$use_acl" = "xauto0"; then
|
||
|
+ AC_MSG_WARN([libacl development library was not found or not usable.])
|
||
|
+ AC_MSG_WARN([AC_PACKAGE_NAME will be built without ACL support.])
|
||
|
+ fi
|
||
|
+ fi
|
||
|
+ AC_SUBST([LIB_ACL])
|
||
|
+ AC_DEFINE_UNQUOTED([USE_ACL], [$use_acl],
|
||
|
+ [Define to nonzero if you want access control list support.])
|
||
|
+ USE_ACL=$use_acl
|
||
|
+ AC_SUBST([USE_ACL])
|
||
|
+])
|
||
|
+
|
||
|
+# gl_ACL_GET_FILE(IF-WORKS, IF-NOT)
|
||
|
+# -------------------------------------
|
||
|
+# If 'acl_get_file' works (does not have a particular bug),
|
||
|
+# run IF-WORKS, otherwise, IF-NOT.
|
||
|
+# This tests for a Darwin 8.7.0 bug, whereby acl_get_file returns NULL,
|
||
|
+# but sets errno = ENOENT for an existing file or directory.
|
||
|
+AC_DEFUN([gl_ACL_GET_FILE],
|
||
|
+[
|
||
|
+ AC_CACHE_CHECK([for working acl_get_file], [gl_cv_func_working_acl_get_file],
|
||
|
+ [AC_RUN_IFELSE(
|
||
|
+ [AC_LANG_PROGRAM(
|
||
|
+ [[#include <sys/types.h>
|
||
|
+ #include <sys/acl.h>
|
||
|
+ #include <errno.h>
|
||
|
+ ]],
|
||
|
+ [[if (!acl_get_file (".", ACL_TYPE_ACCESS) && errno == ENOENT)
|
||
|
+ return 1;
|
||
|
+ return 0;
|
||
|
+ ]])],
|
||
|
+ [gl_cv_func_working_acl_get_file=yes],
|
||
|
+ [gl_cv_func_working_acl_get_file=no],
|
||
|
+ [gl_cv_func_working_acl_get_file=cross-compiling])])
|
||
|
+
|
||
|
+ AS_IF([test $gl_cv_func_working_acl_get_file = yes], [$1], [$2])
|
||
|
+])
|
||
|
diff --git a/m4/gnulib-comp.m4 b/m4/gnulib-comp.m4
|
||
|
index 837538e..147ecc0 100644
|
||
|
--- a/m4/gnulib-comp.m4
|
||
|
+++ b/m4/gnulib-comp.m4
|
||
|
@@ -1,6 +1,3 @@
|
||
|
-# -*- buffer-read-only: t -*- vi: set ro:
|
||
|
-# DO NOT EDIT! GENERATED AUTOMATICALLY!
|
||
|
-# DO NOT EDIT! GENERATED AUTOMATICALLY!
|
||
|
# Copyright (C) 2002-2011 Free Software Foundation, Inc.
|
||
|
#
|
||
|
# This file is free software, distributed under the terms of the GNU
|
||
|
@@ -256,6 +253,7 @@ AC_DEFUN([gl_INIT],
|
||
|
gl_source_base='gnu'
|
||
|
# Code from module alloca:
|
||
|
# Code from module alloca-opt:
|
||
|
+ gl_FUNC_ACL
|
||
|
gl_FUNC_ALLOCA
|
||
|
# Code from module areadlink:
|
||
|
# Code from module areadlinkat:
|
||
|
@@ -565,6 +563,15 @@ AC_DEFUN([gl_INIT],
|
||
|
gl_SAVE_CWD
|
||
|
# Code from module savedir:
|
||
|
gl_SAVEDIR
|
||
|
+ # Code from module acl:
|
||
|
+ AC_CHECK_HEADERS([selinux/flask.h])
|
||
|
+ AC_LIBOBJ([selinux-at])
|
||
|
+ gl_HEADERS_SELINUX_SELINUX_H
|
||
|
+ gl_HEADERS_SELINUX_CONTEXT_H
|
||
|
+ AC_REQUIRE([AC_C_INLINE])
|
||
|
+ if test "$with_selinux" != no && test "$ac_cv_header_selinux_selinux_h" = yes; then
|
||
|
+ AC_LIBOBJ([getfilecon])
|
||
|
+ fi
|
||
|
# Code from module setenv:
|
||
|
gl_FUNC_SETENV
|
||
|
gl_STDLIB_MODULE_INDICATOR([setenv])
|
||
|
@@ -875,10 +882,14 @@ AC_DEFUN([gltests_LIBSOURCES], [
|
||
|
AC_DEFUN([gl_FILE_LIST], [
|
||
|
build-aux/arg-nonnull.h
|
||
|
build-aux/c++defs.h
|
||
|
+ build-aux/snippet/unused-parameter.h
|
||
|
build-aux/config.rpath
|
||
|
build-aux/gitlog-to-changelog
|
||
|
build-aux/warn-on-use.h
|
||
|
doc/parse-datetime.texi
|
||
|
+ lib/acl-internal.h
|
||
|
+ lib/acl.h
|
||
|
+ lib/acl_entries.c
|
||
|
lib/alloca.c
|
||
|
lib/alloca.in.h
|
||
|
lib/anytostr.c
|
||
|
@@ -928,6 +939,7 @@ AC_DEFUN([gl_FILE_LIST], [
|
||
|
lib/closeout.c
|
||
|
lib/closeout.h
|
||
|
lib/config.charset
|
||
|
+ lib/copy-acl.c
|
||
|
lib/dirent--.h
|
||
|
lib/dirent-safer.h
|
||
|
lib/dirent.in.h
|
||
|
@@ -955,6 +967,7 @@ AC_DEFUN([gl_FILE_LIST], [
|
||
|
lib/fd-safer.c
|
||
|
lib/fdopendir.c
|
||
|
lib/fdutimensat.c
|
||
|
+ lib/file-has-acl.c
|
||
|
lib/fileblocks.c
|
||
|
lib/filenamecat-lgpl.c
|
||
|
lib/filenamecat.h
|
||
|
@@ -1083,6 +1096,11 @@ AC_DEFUN([gl_FILE_LIST], [
|
||
|
lib/save-cwd.h
|
||
|
lib/savedir.c
|
||
|
lib/savedir.h
|
||
|
+ lib/se-context.in.h
|
||
|
+ lib/se-selinux.in.h
|
||
|
+ lib/selinux-at.c
|
||
|
+ lib/selinux-at.h
|
||
|
+ lib/set-mode-acl.c
|
||
|
lib/setenv.c
|
||
|
lib/size_max.h
|
||
|
lib/sleep.c
|
||
|
@@ -1176,6 +1194,7 @@ AC_DEFUN([gl_FILE_LIST], [
|
||
|
lib/xvasprintf.c
|
||
|
lib/xvasprintf.h
|
||
|
m4/00gnulib.m4
|
||
|
+ m4/acl.m4
|
||
|
m4/alloca.m4
|
||
|
m4/argmatch.m4
|
||
|
m4/argp.m4
|
||
|
@@ -1314,6 +1333,8 @@ AC_DEFUN([gl_FILE_LIST], [
|
||
|
m4/safe-write.m4
|
||
|
m4/save-cwd.m4
|
||
|
m4/savedir.m4
|
||
|
+ m4/selinux-context-h.m4
|
||
|
+ m4/selinux-selinux-h.m4
|
||
|
m4/setenv.m4
|
||
|
m4/size_max.m4
|
||
|
m4/sleep.m4
|
||
|
diff --git a/m4/selinux-context-h.m4 b/m4/selinux-context-h.m4
|
||
|
new file mode 100644
|
||
|
index 0000000..7ad67bb
|
||
|
--- /dev/null
|
||
|
+++ b/m4/selinux-context-h.m4
|
||
|
@@ -0,0 +1,22 @@
|
||
|
+# serial 3 -*- Autoconf -*-
|
||
|
+# Copyright (C) 2006-2007, 2009-2012 Free Software Foundation, Inc.
|
||
|
+# This file is free software; the Free Software Foundation
|
||
|
+# gives unlimited permission to copy and/or distribute it,
|
||
|
+# with or without modifications, as long as this notice is preserved.
|
||
|
+
|
||
|
+# From Jim Meyering
|
||
|
+# Provide <selinux/context.h>, if necessary.
|
||
|
+
|
||
|
+AC_DEFUN([gl_HEADERS_SELINUX_CONTEXT_H],
|
||
|
+[
|
||
|
+ AC_REQUIRE([gl_LIBSELINUX])
|
||
|
+ if test "$with_selinux" != no; then
|
||
|
+ AC_CHECK_HEADERS([selinux/context.h],
|
||
|
+ [SELINUX_CONTEXT_H=],
|
||
|
+ [SELINUX_CONTEXT_H=selinux/context.h])
|
||
|
+ else
|
||
|
+ SELINUX_CONTEXT_H=selinux/context.h
|
||
|
+ fi
|
||
|
+ AC_SUBST([SELINUX_CONTEXT_H])
|
||
|
+ AM_CONDITIONAL([GL_GENERATE_SELINUX_CONTEXT_H], [test -n "$SELINUX_CONTEXT_H"])
|
||
|
+])
|
||
|
diff --git a/m4/selinux-selinux-h.m4 b/m4/selinux-selinux-h.m4
|
||
|
new file mode 100644
|
||
|
index 0000000..ed5215b
|
||
|
--- /dev/null
|
||
|
+++ b/m4/selinux-selinux-h.m4
|
||
|
@@ -0,0 +1,69 @@
|
||
|
+# serial 5 -*- Autoconf -*-
|
||
|
+# Copyright (C) 2006-2007, 2009-2012 Free Software Foundation, Inc.
|
||
|
+# This file is free software; the Free Software Foundation
|
||
|
+# gives unlimited permission to copy and/or distribute it,
|
||
|
+# with or without modifications, as long as this notice is preserved.
|
||
|
+
|
||
|
+# From Jim Meyering
|
||
|
+# Provide <selinux/selinux.h>, if necessary.
|
||
|
+# If it is already present, provide wrapper functions to guard against
|
||
|
+# misbehavior from getfilecon, lgetfilecon, and fgetfilecon.
|
||
|
+
|
||
|
+AC_DEFUN([gl_HEADERS_SELINUX_SELINUX_H],
|
||
|
+[
|
||
|
+ AC_REQUIRE([gl_LIBSELINUX])
|
||
|
+ if test "$with_selinux" != no; then
|
||
|
+ AC_CHECK_HEADERS([selinux/selinux.h])
|
||
|
+
|
||
|
+ 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.
|
||
|
+ gl_CHECK_NEXT_HEADERS([selinux/selinux.h])
|
||
|
+ AC_DEFINE([getfilecon], [rpl_getfilecon],
|
||
|
+ [Always use our getfilecon wrapper.])
|
||
|
+ AC_DEFINE([lgetfilecon], [rpl_lgetfilecon],
|
||
|
+ [Always use our lgetfilecon wrapper.])
|
||
|
+ AC_DEFINE([fgetfilecon], [rpl_fgetfilecon],
|
||
|
+ [Always use our fgetfilecon wrapper.])
|
||
|
+ fi
|
||
|
+
|
||
|
+ case "$ac_cv_search_setfilecon:$ac_cv_header_selinux_selinux_h" in
|
||
|
+ no:*) # already warned
|
||
|
+ ;;
|
||
|
+ *:no)
|
||
|
+ AC_MSG_WARN([libselinux was found but selinux/selinux.h is missing.])
|
||
|
+ AC_MSG_WARN([AC_PACKAGE_NAME will be compiled without SELinux support.])
|
||
|
+ esac
|
||
|
+ else
|
||
|
+ # Do as if <selinux/selinux.h> does not exist, even if
|
||
|
+ # AC_CHECK_HEADERS_ONCE has already determined that it exists.
|
||
|
+ AC_DEFINE([HAVE_SELINUX_SELINUX_H], [0])
|
||
|
+ fi
|
||
|
+])
|
||
|
+
|
||
|
+AC_DEFUN([gl_LIBSELINUX],
|
||
|
+[
|
||
|
+ AC_REQUIRE([AC_CANONICAL_HOST])
|
||
|
+ AC_REQUIRE([AC_CANONICAL_BUILD])
|
||
|
+
|
||
|
+ AC_ARG_WITH([selinux],
|
||
|
+ AS_HELP_STRING([--without-selinux], [do not use SELinux, even on systems with SELinux]),
|
||
|
+ [], [with_selinux=maybe])
|
||
|
+
|
||
|
+ LIB_SELINUX=
|
||
|
+ if test "$with_selinux" != no; then
|
||
|
+ gl_save_LIBS=$LIBS
|
||
|
+ AC_SEARCH_LIBS([setfilecon], [selinux],
|
||
|
+ [test "$ac_cv_search_setfilecon" = "none required" ||
|
||
|
+ LIB_SELINUX=$ac_cv_search_setfilecon])
|
||
|
+ LIBS=$gl_save_LIBS
|
||
|
+ fi
|
||
|
+ AC_SUBST([LIB_SELINUX])
|
||
|
+
|
||
|
+ # Warn if SELinux is found but libselinux is absent;
|
||
|
+ if test "$ac_cv_search_setfilecon" = no &&
|
||
|
+ test "$host" = "$build" && test -d /selinux; then
|
||
|
+ AC_MSG_WARN([This system supports SELinux but libselinux is missing.])
|
||
|
+ AC_MSG_WARN([AC_PACKAGE_NAME will be compiled without SELinux support.])
|
||
|
+ fi
|
||
|
+])
|
||
|
--
|
||
|
1.8.1.2
|