diff options
author | Nathan Scott <nathans@sgi.com> | 2003-02-26 06:29:15 +0000 |
---|---|---|
committer | Nathan Scott <nathans@sgi.com> | 2003-02-26 06:29:15 +0000 |
commit | d01f83eda36a1cc8f9b369d0ff376c74a64771ec (patch) | |
tree | f807ab6642ac88c1d15cf0fb3466348d23a31166 /libacl | |
parent | 38a1dc504c6f43bb1ebafa64882886d9a9a13ce7 (diff) | |
download | acl-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/Makefile | 18 | ||||
-rw-r--r-- | libacl/__apply_mask_to_mode.c | 46 | ||||
-rw-r--r-- | libacl/libacl.h | 1 | ||||
-rw-r--r-- | libacl/perm_copy.h | 20 | ||||
-rw-r--r-- | libacl/perm_copy_fd.c | 202 | ||||
-rw-r--r-- | libacl/perm_copy_file.c | 239 |
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 +} + |