summaryrefslogtreecommitdiff
path: root/libacl
diff options
context:
space:
mode:
authorNathan Scott <nathans@sgi.com>2003-02-26 06:29:15 +0000
committerNathan Scott <nathans@sgi.com>2003-02-26 06:29:15 +0000
commitd01f83eda36a1cc8f9b369d0ff376c74a64771ec (patch)
treef807ab6642ac88c1d15cf0fb3466348d23a31166 /libacl
parent38a1dc504c6f43bb1ebafa64882886d9a9a13ce7 (diff)
downloadacl-d01f83eda36a1cc8f9b369d0ff376c74a64771ec.tar.gz
An ACL userspace update from Andreas - adds in permissions copying routines
and symbol versioning for libacl.
Diffstat (limited to 'libacl')
-rw-r--r--libacl/Makefile18
-rw-r--r--libacl/__apply_mask_to_mode.c46
-rw-r--r--libacl/libacl.h1
-rw-r--r--libacl/perm_copy.h20
-rw-r--r--libacl/perm_copy_fd.c202
-rw-r--r--libacl/perm_copy_file.c239
6 files changed, 520 insertions, 6 deletions
diff --git a/libacl/Makefile b/libacl/Makefile
index b9349fa..48bbdff 100644
--- a/libacl/Makefile
+++ b/libacl/Makefile
@@ -32,16 +32,22 @@
#
TOPDIR = ..
+
+LTLDFLAGS = -Wl,--version-script,$(TOPDIR)/exports
include $(TOPDIR)/include/builddefs
LTLIBRARY = libacl.la
LTLIBS = -lattr
-LT_CURRENT = 1
-LT_REVISION = 4
-LT_AGE = 0
+LT_CURRENT = 2
+LT_REVISION = 0
+LT_AGE = 1
+
+CFILES = $(POSIX_CFILES) $(LIBACL_CFILES) $(INTERNAL_CFILES) \
+ perm_copy_fd.c perm_copy_file.c
+HFILES = libobj.h libacl.h byteorder.h __acl_from_xattr.h __acl_to_xattr.h \
+ perm_copy.h
-CFILES = $(POSIX_CFILES) $(LIBACL_CFILES) $(INTERNAL_CFILES)
-HFILES = libobj.h libacl.h byteorder.h __acl_from_xattr.h __acl_to_xattr.h
+LCFLAGS = -include perm_copy.h
POSIX_CFILES = \
acl_add_perm.c acl_calc_mask.c acl_clear_perms.c acl_copy_entry.c \
@@ -59,7 +65,7 @@ LIBACL_CFILES = \
INTERNAL_CFILES = \
__acl_to_any_text.c __acl_to_xattr.c __acl_from_xattr.c \
- __acl_reorder_obj_p.c __libobj.c
+ __acl_reorder_obj_p.c __libobj.c __apply_mask_to_mode.c
default: $(LTLIBRARY)
diff --git a/libacl/__apply_mask_to_mode.c b/libacl/__apply_mask_to_mode.c
new file mode 100644
index 0000000..400e007
--- /dev/null
+++ b/libacl/__apply_mask_to_mode.c
@@ -0,0 +1,46 @@
+#include <sys/stat.h>
+#include <acl/libacl.h>
+#include "libacl.h"
+
+#if defined(HAVE_ACL_ENTRIES) && \
+ defined (HAVE_ACL_GET_ENTRY) && defined(HAVE_ACL_GET_TAG_TYPE) && \
+ defined (HAVE_ACL_GET_PERMSET) && defined(HAVE_ACL_GET_PERM)
+int
+__apply_mask_to_mode(mode_t *mode, acl_t acl)
+{
+ acl_entry_t entry;
+ int entry_id=ACL_FIRST_ENTRY;
+
+ /* A mimimal ACL which has three entries has no mask entry; the
+ group file mode permission bits are exact. */
+ if (acl_entries(acl) == 3)
+ return 0;
+
+ while (acl_get_entry(acl, entry_id, &entry) == 1) {
+ acl_tag_t tag_type;
+
+ acl_get_tag_type(entry, &tag_type);
+ if (tag_type == ACL_MASK) {
+ acl_permset_t permset;
+
+ acl_get_permset(entry, &permset);
+ if (acl_get_perm(permset, ACL_READ) != 1)
+ *mode &= ~S_IRGRP;
+ if (acl_get_perm(permset, ACL_WRITE) != 1)
+ *mode &= ~S_IWGRP;
+ if (acl_get_perm(permset, ACL_EXECUTE) != 1)
+ *mode &= ~S_IXGRP;
+
+ return 0;
+ }
+ entry_id = ACL_NEXT_ENTRY;
+ }
+
+ /* This is unexpected; if the ACL didn't include a mask entry
+ we should have exited before the loop! */
+ *mode &= ~S_IRWXG;
+ return 1;
+}
+#endif
+
+
diff --git a/libacl/libacl.h b/libacl/libacl.h
index 9a443ac..51f4b66 100644
--- a/libacl/libacl.h
+++ b/libacl/libacl.h
@@ -115,6 +115,7 @@ extern void __acl_free_acl_obj(acl_obj *acl_obj_p) hidden;
extern char *__acl_to_any_text(acl_t acl, ssize_t *len_p,
const char *prefix, char separator,
const char *suffix, int options) hidden;
+extern int __apply_mask_to_mode(mode_t *mode, acl_t acl) hidden;
#define FOREACH_ACL_ENTRY(entry_obj_p, acl_obj_p) \
for( (entry_obj_p) = (acl_obj_p)->anext; \
diff --git a/libacl/perm_copy.h b/libacl/perm_copy.h
new file mode 100644
index 0000000..d47999b
--- /dev/null
+++ b/libacl/perm_copy.h
@@ -0,0 +1,20 @@
+/* Features we always have */
+
+#define HAVE_ACL_LIBACL_H 1
+#define HAVE_CONFIG_H 1
+#define HAVE_SYS_ACL_H 1
+#define HAVE_LIBACL_LIBACL_H 1
+
+#define HAVE_ACL_DELETE_DEF_FILE 1
+#define HAVE_ACL_ENTRIES 1
+#define HAVE_ACL_FREE 1
+#define HAVE_ACL_FROM_MODE 1
+#define HAVE_ACL_FROM_TEXT 1
+#define HAVE_ACL_GET_ENTRY 1
+#define HAVE_ACL_GET_FD 1
+#define HAVE_ACL_GET_FILE 1
+#define HAVE_ACL_GET_PERM 1
+#define HAVE_ACL_GET_PERMSET 1
+#define HAVE_ACL_GET_TAG_TYPE 1
+#define HAVE_ACL_SET_FD 1
+#define HAVE_ACL_SET_FILE 1
diff --git a/libacl/perm_copy_fd.c b/libacl/perm_copy_fd.c
new file mode 100644
index 0000000..9ddb91c
--- /dev/null
+++ b/libacl/perm_copy_fd.c
@@ -0,0 +1,202 @@
+/* Copy POSIX 1003.1e draft 17 (abandoned) ACLs between files. */
+
+/* Copyright (C) 2002 Andreas Gruenbacher <agruen@suse.de>, SuSE Linux AG.
+
+ 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 2, 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; see the file COPYING. If not, write to the Free
+ Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
+
+#if defined (HAVE_CONFIG_H)
+#include "config.h"
+#endif
+#if defined(HAVE_LIBACL_LIBACL_H)
+# include "libacl.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#if defined(HAVE_SYS_ACL_H)
+#include <sys/acl.h>
+#endif
+
+#if defined(HAVE_ACL_LIBACL_H)
+#include <acl/libacl.h>
+#endif
+
+#define ERROR_CONTEXT_MACROS
+#ifdef HAVE_ATTR_ERROR_CONTEXT_H
+#include <attr/error_context.h>
+#else
+#include "error_context.h"
+#endif
+
+#if !defined(ENOTSUP)
+# define ENOTSUP (-1)
+#endif
+
+#if !defined(HAVE_ACL_FREE)
+static int
+acl_free(void *obj_p)
+{
+ free (obj_p);
+ return 0;
+}
+#endif
+
+#if !defined(HAVE_ACL_ENTRIES)
+static int
+acl_entries(acl_t acl)
+{
+# if defined(HAVE_ACL_GET_ENTRY)
+ /* POSIX 1003.1e draft 17 (abandoned) compatible version. */
+ acl_entry_t entry;
+ int entries = 0;
+
+ int entries = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry);
+ if (entries > 0) {
+ while (acl_get_entry(acl, ACL_NEXT_ENTRY, &entry) > 0)
+ entries++;
+ }
+ return entries;
+# else
+ return -1;
+# endif
+}
+#endif
+
+#if !defined(HAVE_ACL_FROM_MODE) && defined(HAVE_ACL_FROM_TEXT)
+# define HAVE_ACL_FROM_MODE
+static acl_t
+acl_from_mode(mode_t mode)
+{
+ char acl_text[] = "u::---,g::---,o::---";
+ acl_t acl;
+
+ 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';
+
+ return acl_from_text (acl_text);
+}
+#endif
+
+/* Set the access control list of path to the permissions defined by mode. */
+static int
+set_acl_fd (char const *path, int fd, mode_t mode, struct error_context *ctx)
+{
+ int ret = 0;
+#if defined(HAVE_ACL_FROM_MODE) && defined(HAVE_ACL_SET_FD)
+ /* POSIX 1003.1e draft 17 (abandoned) specific version. */
+ acl_t acl = acl_from_mode (mode);
+ if (!acl) {
+ error (ctx, "");
+ return -1;
+ }
+
+ if (acl_set_fd (fd, acl) != 0) {
+ ret = -1;
+ if (errno == ENOTSUP || errno == ENOSYS) {
+ (void) acl_free (acl);
+ goto chmod_only;
+ } else {
+ const char *qpath = quote (ctx, path);
+ error (ctx, _("setting permissions for %s"), qpath);
+ quote_free (ctx, qpath);
+ }
+ }
+ (void) acl_free (acl);
+ return ret;
+#endif
+
+chmod_only:
+ ret = fchmod (fd, mode);
+ if (ret != 0) {
+ const char *qpath = quote (ctx, path);
+ error (ctx, _("setting permissions for %s"), qpath);
+ quote_free (ctx, qpath);
+ }
+ return ret;
+}
+
+/* Copy the permissions of src_path to dst_path. This includes the
+ file mode permission bits and ACLs. File ownership is not copied.
+ */
+int
+perm_copy_fd (const char *src_path, int src_fd,
+ const char *dst_path, int dst_fd,
+ struct error_context *ctx)
+{
+ struct stat st;
+ int ret = 0;
+
+ ret = fstat(src_fd, &st);
+ if (ret != 0) {
+ const char *qpath = quote (ctx, src_path);
+ error (ctx, "%s", qpath);
+ quote_free (ctx, qpath);
+ return -1;
+ }
+#if defined(HAVE_ACL_GET_FD) && defined(HAVE_ACL_SET_FD)
+ {
+ /* POSIX 1003.1e draft 17 (abandoned) specific version. */
+ acl_t acl = acl_get_fd (src_fd);
+ if (acl == NULL) {
+ ret = -1;
+ if (errno == ENOSYS || errno == ENOTSUP)
+ ret = set_acl_fd (dst_path, dst_fd, st.st_mode, ctx);
+ else {
+ const char *qpath = quote (ctx, src_path);
+ error (ctx, "%s", qpath);
+ quote_free (ctx, qpath);
+ }
+ return ret;
+ }
+
+ if (acl_set_fd (dst_fd, acl) != 0) {
+ int saved_errno = errno;
+ __apply_mask_to_mode(&st.st_mode, acl);
+ ret = fchmod (dst_fd, st.st_mode);
+ if ((errno != ENOSYS && errno != ENOTSUP) ||
+ acl_entries (acl) != 3) {
+ const char *qpath = quote (ctx, dst_path);
+ errno = saved_errno;
+ error (ctx, _("preserving permissions for %s"), qpath);
+ quote_free (ctx, qpath);
+ ret = -1;
+ }
+ }
+ (void) acl_free (acl);
+ return ret;
+ }
+#else
+ /* POSIX.1 version. */
+ ret = fchmod (dst_fd, st.st_mode);
+ if (ret != 0) {
+ const char *qpath = quote (ctx, dst_path);
+ error (ctx, _("setting permissions for %s"), qpath);
+ quote_free (ctx, qpath);
+ }
+ return ret;
+#endif
+}
+
diff --git a/libacl/perm_copy_file.c b/libacl/perm_copy_file.c
new file mode 100644
index 0000000..5586438
--- /dev/null
+++ b/libacl/perm_copy_file.c
@@ -0,0 +1,239 @@
+/* Copy POSIX 1003.1e draft 17 (abandoned) ACLs between files. */
+
+/* Copyright (C) 2002 Andreas Gruenbacher <agruen@suse.de>, SuSE Linux AG.
+
+ 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 2, 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; see the file COPYING. If not, write to the Free
+ Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
+
+#if defined (HAVE_CONFIG_H)
+#include "config.h"
+#endif
+#if defined(HAVE_LIBACL_LIBACL_H)
+# include "libacl.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#if defined(HAVE_SYS_ACL_H)
+#include <sys/acl.h>
+#endif
+
+#if defined(HAVE_ACL_LIBACL_H)
+#include <acl/libacl.h>
+#endif
+
+#define ERROR_CONTEXT_MACROS
+#ifdef HAVE_ATTR_ERROR_CONTEXT_H
+#include <attr/error_context.h>
+#else
+#include "error_context.h"
+#endif
+
+#if !defined(ENOTSUP)
+# define ENOTSUP (-1)
+#endif
+
+#if !defined(HAVE_ACL_FREE)
+static int
+acl_free(void *obj_p)
+{
+ free (obj_p);
+ return 0;
+}
+#endif
+
+#if !defined(HAVE_ACL_ENTRIES)
+static int
+acl_entries(acl_t acl)
+{
+# if defined(HAVE_ACL_GET_ENTRY)
+ /* POSIX 1003.1e draft 17 (abandoned) compatible version. */
+ acl_entry_t entry;
+ int entries = 0;
+
+ int entries = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry);
+ if (entries > 0) {
+ while (acl_get_entry(acl, ACL_NEXT_ENTRY, &entry) > 0)
+ entries++;
+ }
+ return entries;
+# else
+ return -1;
+# endif
+}
+#endif
+
+#if !defined(HAVE_ACL_FROM_MODE) && defined(HAVE_ACL_FROM_TEXT)
+# define HAVE_ACL_FROM_MODE
+static acl_t
+acl_from_mode(mode_t mode)
+{
+ char acl_text[] = "u::---,g::---,o::---";
+ acl_t acl;
+
+ 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';
+
+ return acl_from_text (acl_text);
+}
+#endif
+
+/* Set the access control list of path to the permissions defined by mode. */
+static int
+set_acl (char const *path, mode_t mode, struct error_context *ctx)
+{
+ int ret = 0;
+#if defined(HAVE_ACL_FROM_MODE) && defined(HAVE_ACL_SET_FILE)
+ /* POSIX 1003.1e draft 17 (abandoned) specific version. */
+ acl_t acl = acl_from_mode (mode);
+ if (!acl) {
+ error (ctx, "");
+ return -1;
+ }
+
+ if (acl_set_file (path, ACL_TYPE_ACCESS, acl) != 0) {
+ ret = -1;
+ if (errno == ENOTSUP || errno == ENOSYS) {
+ (void) acl_free (acl);
+ goto chmod_only;
+ } else {
+ const char *qpath = quote (ctx, path);
+ error (ctx, _("setting permissions for %s"), qpath);
+ quote_free (ctx, qpath);
+ }
+ }
+ (void) acl_free (acl);
+ if (ret == 0 && S_ISDIR (mode)) {
+# if defined(HAVE_ACL_DELETE_DEF_FILE)
+ ret = acl_delete_def_file (path);
+# else
+ acl = acl_init (0);
+ ret = acl_set_file (path, ACL_TYPE_DEFAULT, acl);
+ (void) acl_free (acl);
+# endif
+ if (ret != 0) {
+ const char *qpath = quote (ctx, path);
+ error (ctx, _( "setting permissions for %s"), qpath);
+ quote_free (ctx, qpath);
+ }
+ }
+ return ret;
+#endif
+
+chmod_only:
+ ret = chmod (path, mode);
+ if (ret != 0) {
+ const char *qpath = quote (ctx, path);
+ error (ctx, _("setting permissions for %s"), qpath);
+ quote_free (ctx, qpath);
+ }
+ return ret;
+}
+
+/* Copy the permissions of src_path to dst_path. This includes the
+ file mode permission bits and ACLs. File ownership is not copied.
+ */
+int
+perm_copy_file (const char *src_path, const char *dst_path,
+ struct error_context *ctx)
+{
+ struct stat st;
+ int ret = 0;
+
+ ret = stat(src_path, &st);
+ if (ret != 0) {
+ const char *qpath = quote (ctx, src_path);
+ error (ctx, "%s", qpath);
+ quote_free (ctx, qpath);
+ return -1;
+ }
+#if defined(HAVE_ACL_GET_FILE) && defined(HAVE_ACL_SET_FILE)
+ {
+ /* POSIX 1003.1e draft 17 (abandoned) specific version. */
+ acl_t acl = acl_get_file (src_path, ACL_TYPE_ACCESS);
+ if (acl == NULL) {
+ ret = -1;
+ if (errno == ENOSYS || errno == ENOTSUP)
+ ret = set_acl (dst_path, st.st_mode, ctx);
+ else {
+ const char *qpath = quote (ctx, src_path);
+ error (ctx, "%s", qpath);
+ quote_free (ctx, qpath);
+ }
+ return ret;
+ }
+
+ if (acl_set_file (dst_path, ACL_TYPE_ACCESS, acl) != 0) {
+ int saved_errno = errno;
+ __apply_mask_to_mode(&st.st_mode, acl);
+ ret = chmod (dst_path, st.st_mode);
+ if ((errno != ENOSYS && errno != ENOTSUP) ||
+ acl_entries (acl) != 3) {
+ const char *qpath = quote (ctx, dst_path);
+ errno = saved_errno;
+ error (ctx, _("preserving permissions for %s"), qpath);
+ quote_free (ctx, qpath);
+ ret = -1;
+ }
+ }
+ (void) acl_free (acl);
+
+ if (ret == 0 && S_ISDIR (st.st_mode)) {
+ acl = acl_get_file (src_path, ACL_TYPE_DEFAULT);
+ if (acl == NULL) {
+ const char *qpath = quote (ctx, src_path);
+ error (ctx, "%s", qpath);
+ quote_free (ctx, qpath);
+ return -1;
+ }
+# if defined(HAVE_ACL_DELETE_DEF_FILE)
+ if (acl_entries(acl) == 0)
+ ret = acl_delete_def_file(dst_path);
+ else
+ ret = acl_set_file (dst_path, ACL_TYPE_DEFAULT, acl);
+# else
+ ret = acl_set_file (dst_path, ACL_TYPE_DEFAULT, acl);
+# endif
+ if (ret != 0) {
+ const char *qpath = quote (ctx, dst_path);
+ error (ctx, _("preserving permissions for %s"), qpath);
+ quote_free (ctx, qpath);
+ }
+ (void) acl_free(acl);
+ }
+ return ret;
+ }
+#else
+ /* POSIX.1 version. */
+ ret = chmod (dst_path, st.st_mode);
+ if (ret != 0) {
+ const char *qpath = quote (ctx, dst_path);
+ error (ctx, _("setting permissions for %s"), qpath);
+ quote_free (ctx, qpath);
+ }
+ return ret;
+#endif
+}
+