X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Ftar;a=blobdiff_plain;f=src%2Fxattrs.c;h=dbe496620572a7f23c07e8f16bf037d2cf96b9b8;hp=a3f0b5f5b8740f5e43b822bfa6a5949ad571f711;hb=45ccda119355a1087450039a250359c1d0de0d08;hpb=d36f5a3cc3280d6c4a58367bf51b527d5c14ac04 diff --git a/src/xattrs.c b/src/xattrs.c index a3f0b5f..dbe4966 100644 --- a/src/xattrs.c +++ b/src/xattrs.c @@ -1,23 +1,23 @@ /* Support for extended attributes. - Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software - Foundation, Inc. + Copyright (C) 2006-2014 Free Software Foundation, Inc. - Written by James Antill, on 2006-07-27. + This file is part of GNU tar. - 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. + GNU tar 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. + GNU tar 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, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Written by James Antill, on 2006-07-27. */ #include #include @@ -28,12 +28,13 @@ #include "common.h" #include "xattr-at.h" +#include "selinux-at.h" struct xattrs_mask_map { const char **masks; - int size; - int used; + size_t size; + size_t used; }; /* list of fnmatch patterns */ @@ -57,9 +58,9 @@ static struct #ifdef HAVE_POSIX_ACLS /* acl-at wrappers, TODO: move to gnulib in future? */ -acl_t acl_get_file_at (int dirfd, const char *file, acl_type_t type); -int acl_set_file_at (int dirfd, const char *file, acl_type_t type, acl_t acl); -int file_has_acl_at (int dirfd, char const *, struct stat const *); +static acl_t acl_get_file_at (int, const char *, acl_type_t); +static int acl_set_file_at (int, const char *, acl_type_t, acl_t); +static int file_has_acl_at (int, char const *, struct stat const *); /* acl_get_file_at */ #define AT_FUNC_NAME acl_get_file_at @@ -99,58 +100,69 @@ int file_has_acl_at (int dirfd, char const *, struct stat const *); #undef AT_FUNC_POST_FILE_ARGS /* convert unix permissions into an ACL ... needed due to "default" ACLs */ -static acl_t perms2acl (int perms) +static acl_t +perms2acl (int perms) { char val[] = "user::---,group::---,other::---"; /* 0123456789 123456789 123456789 123456789 */ - /* user */ - if (perms & 0400) val[ 6] = 'r'; - if (perms & 0200) val[ 7] = 'w'; - if (perms & 0100) val[ 8] = 'x'; + /* user */ + if (perms & 0400) + val[6] = 'r'; + if (perms & 0200) + val[7] = 'w'; + if (perms & 0100) + val[8] = 'x'; /* group */ - if (perms & 0040) val[17] = 'r'; - if (perms & 0020) val[18] = 'w'; - if (perms & 0010) val[19] = 'x'; + if (perms & 0040) + val[17] = 'r'; + if (perms & 0020) + val[18] = 'w'; + if (perms & 0010) + val[19] = 'x'; /* other */ - if (perms & 0004) val[28] = 'r'; - if (perms & 0002) val[29] = 'w'; - if (perms & 0001) val[30] = 'x'; - - return (acl_from_text (val)); + if (perms & 0004) + val[28] = 'r'; + if (perms & 0002) + val[29] = 'w'; + if (perms & 0001) + val[30] = 'x'; + + return acl_from_text (val); } -static char *skip_to_ext_fields (char *ptr) +static char * +skip_to_ext_fields (char *ptr) { - ptr += strcspn (ptr, ":,\n"); /* skip tag name. Ie. user/group/default/mask */ + /* skip tag name (user/group/default/mask) */ + ptr += strcspn (ptr, ":,\n"); if (*ptr != ':') - return (ptr); /* error? no user/group field */ + return ptr; ++ptr; ptr += strcspn (ptr, ":,\n"); /* skip user/group name */ if (*ptr != ':') - return (ptr); /* error? no perms field */ + return ptr; ++ptr; ptr += strcspn (ptr, ":,\n"); /* skip perms */ - if (*ptr != ':') - return (ptr); /* no extra fields */ - - return (ptr); + return ptr; } /* The POSIX draft allows extra fields after the three main ones. Star uses this to add a fourth field for user/group which is the numeric ID. - We just skip all extra fields atm. */ -static const char *fixup_extra_acl_fields (const char *ptr) + This function removes such extra fields by overwriting them with the + characters that follow. */ +static char * +fixup_extra_acl_fields (char *ptr) { - char *src = (char *)ptr; - char *dst = (char *)ptr; + char *src = ptr; + char *dst = ptr; while (*src) { @@ -159,14 +171,15 @@ static const char *fixup_extra_acl_fields (const char *ptr) src = skip_to_ext_fields (src); len = src - old; - if (old != dst) memmove (dst, old, len); + if (old != dst) + memmove (dst, old, len); dst += len; - if (*src == ':') /* We have extra fields, skip them all */ + if (*src == ':') /* We have extra fields, skip them all */ src += strcspn (src, "\n,"); if ((*src == '\n') || (*src == ',')) - *dst++ = *src++; /* also done when dst == src, but that's ok */ + *dst++ = *src++; /* also done when dst == src, but that's ok */ } if (src != dst) *dst = 0; @@ -174,10 +187,12 @@ static const char *fixup_extra_acl_fields (const char *ptr) return ptr; } -static void xattrs__acls_set (struct tar_stat_info const *st, - char const *file_name, int type, - const char *ptr, size_t len, bool def) -{ /* "system.posix_acl_access" */ +/* "system.posix_acl_access" */ +static void +xattrs__acls_set (struct tar_stat_info const *st, + char const *file_name, int type, + char *ptr, size_t len, bool def) +{ acl_t acl; if (ptr) @@ -191,10 +206,10 @@ static void xattrs__acls_set (struct tar_stat_info const *st, else if (acls_option > 0) acl = perms2acl (st->stat.st_mode); else - return; /* don't call acl functions unless we first hit an ACL, or - --acls was passed explicitly */ + return; /* don't call acl functions unless we first hit an ACL, or + --acls was passed explicitly */ - if (acl == (acl_t)NULL) + if (!acl) { call_arg_warn ("acl_from_text", file_name); return; @@ -202,22 +217,24 @@ static void xattrs__acls_set (struct tar_stat_info const *st, if (acl_set_file_at (chdir_fd, file_name, type, acl) == -1) /* warn even if filesystem does not support acls */ - WARNOPT (WARN_XATTR_WRITE, (0, errno, - _("acl_set_file_at: Cannot set POSIX ACLs for file '%s'"), file_name)); + WARNOPT (WARN_XATTR_WRITE, + (0, errno, + _ ("acl_set_file_at: Cannot set POSIX ACLs for file '%s'"), + file_name)); acl_free (acl); } -static void xattrs__acls_get_a (int parentfd, const char *file_name, - struct tar_stat_info *st, - char **ret_ptr, size_t *ret_len) -{ /* "system.posix_acl_access" */ +static void +xattrs__acls_get_a (int parentfd, const char *file_name, + struct tar_stat_info *st, + char **ret_ptr, size_t * ret_len) +{ char *val = NULL; ssize_t len; acl_t acl; - if ((acl = acl_get_file_at (parentfd, file_name, ACL_TYPE_ACCESS)) - == (acl_t)NULL) + if (!(acl = acl_get_file_at (parentfd, file_name, ACL_TYPE_ACCESS))) { if (errno != ENOTSUP) call_arg_warn ("acl_get_file_at", file_name); @@ -227,7 +244,7 @@ static void xattrs__acls_get_a (int parentfd, const char *file_name, val = acl_to_text (acl, &len); acl_free (acl); - if (val == NULL) + if (!val) { call_arg_warn ("acl_to_text", file_name); return; @@ -239,16 +256,17 @@ static void xattrs__acls_get_a (int parentfd, const char *file_name, acl_free (val); } -static void xattrs__acls_get_d (int parentfd, char const *file_name, - struct tar_stat_info *st, - char **ret_ptr, size_t *ret_len) -{ /* "system.posix_acl_default" */ +/* "system.posix_acl_default" */ +static void +xattrs__acls_get_d (int parentfd, char const *file_name, + struct tar_stat_info *st, + char **ret_ptr, size_t * ret_len) +{ char *val = NULL; ssize_t len; acl_t acl; - if ((acl = acl_get_file_at (parentfd, file_name, ACL_TYPE_DEFAULT)) - == (acl_t)NULL) + if (!(acl = acl_get_file_at (parentfd, file_name, ACL_TYPE_DEFAULT))) { if (errno != ENOTSUP) call_arg_warn ("acl_get_file_at", file_name); @@ -258,7 +276,7 @@ static void xattrs__acls_get_d (int parentfd, char const *file_name, val = acl_to_text (acl, &len); acl_free (acl); - if (val == NULL) + if (!val) { call_arg_warn ("acl_to_text", file_name); return; @@ -271,19 +289,20 @@ static void xattrs__acls_get_d (int parentfd, char const *file_name, } #endif /* HAVE_POSIX_ACLS */ -static void acls_one_line (const char *prefix, char delim, - const char *aclstring, size_t len) +static void +acls_one_line (const char *prefix, char delim, + const char *aclstring, size_t len) { /* support both long and short text representation of posix acls */ struct obstack stk; - obstack_init (&stk); int pref_len = strlen (prefix); const char *oldstring = aclstring; + int pos = 0; if (!aclstring || !len) return; - int pos = 0; + obstack_init (&stk); while (pos <= len) { int move = strcspn (aclstring, ",\n"); @@ -300,22 +319,22 @@ static void acls_one_line (const char *prefix, char delim, } obstack_1grow (&stk, '\0'); - const char *toprint = obstack_finish (&stk); - fprintf (stdlis, "%s", toprint); + fprintf (stdlis, "%s", (char *) obstack_finish (&stk)); obstack_free (&stk, NULL); } -void xattrs_acls_get (int parentfd, char const *file_name, - struct tar_stat_info *st, int fd, int xisfile) +void +xattrs_acls_get (int parentfd, char const *file_name, + struct tar_stat_info *st, int fd, int xisfile) { if (acls_option > 0) { #ifndef HAVE_POSIX_ACLS static int done = 0; if (!done) - WARN ((0, 0, _("POSIX ACL support is not available"))); + WARN ((0, 0, _("POSIX ACL support is not available"))); done = 1; #else int err = file_has_acl_at (parentfd, file_name, &st->stat); @@ -336,10 +355,11 @@ void xattrs_acls_get (int parentfd, char const *file_name, } } -void xattrs_acls_set (struct tar_stat_info const *st, - char const *file_name, char typeflag) +void +xattrs_acls_set (struct tar_stat_info const *st, + char const *file_name, char typeflag) { - if ((acls_option > 0) && (typeflag != SYMTYPE)) + if (acls_option > 0 && typeflag != SYMTYPE) { #ifndef HAVE_POSIX_ACLS static int done = 0; @@ -349,34 +369,29 @@ void xattrs_acls_set (struct tar_stat_info const *st, #else xattrs__acls_set (st, file_name, ACL_TYPE_ACCESS, st->acls_a_ptr, st->acls_a_len, false); - if ((typeflag == DIRTYPE) || (typeflag == GNUTYPE_DUMPDIR)) + if (typeflag == DIRTYPE || typeflag == GNUTYPE_DUMPDIR) xattrs__acls_set (st, file_name, ACL_TYPE_DEFAULT, st->acls_d_ptr, st->acls_d_len, true); #endif } } -static void mask_map_realloc (struct xattrs_mask_map *map) +static void +mask_map_realloc (struct xattrs_mask_map *map) { - if (map->size == 0) - { - map->size = 4; - map->masks = xmalloc (16 * sizeof (char *)); - return; - } - - if (map->size <= map->used) + if (map->used == map->size) { - map->size *= 2; - map->masks = xrealloc (map->masks, map->size * sizeof (char *)); - return; + if (map->size == 0) + map->size = 4; + map->masks = x2nrealloc (map->masks, &map->size, sizeof (map->masks[0])); } } -void xattrs_mask_add (const char *mask, bool incl) +void +xattrs_mask_add (const char *mask, bool incl) { - struct xattrs_mask_map *mask_map = incl ? &xattrs_setup.incl - : &xattrs_setup.excl; + struct xattrs_mask_map *mask_map = + incl ? &xattrs_setup.incl : &xattrs_setup.excl; /* ensure there is enough space */ mask_map_realloc (mask_map); /* just assign pointers -- we silently expect that pointer "mask" is valid @@ -384,13 +399,15 @@ void xattrs_mask_add (const char *mask, bool incl) mask_map->masks[mask_map->used++] = mask; } -static void clear_mask_map (struct xattrs_mask_map *mask_map) +static void +clear_mask_map (struct xattrs_mask_map *mask_map) { if (mask_map->size) free (mask_map->masks); } -void xattrs_clear_setup () +void +xattrs_clear_setup (void) { clear_mask_map (&xattrs_setup.incl); clear_mask_map (&xattrs_setup.excl); @@ -398,8 +415,9 @@ void xattrs_clear_setup () /* get all xattrs from file given by FILE_NAME or FD (when non-zero). This includes all the user.*, security.*, system.*, etc. available domains */ -void xattrs_xattrs_get (int parentfd, char const *file_name, - struct tar_stat_info *st, int fd) +void +xattrs_xattrs_get (int parentfd, char const *file_name, + struct tar_stat_info *st, int fd) { if (xattrs_option > 0) { @@ -409,19 +427,20 @@ void xattrs_xattrs_get (int parentfd, char const *file_name, WARN ((0, 0, _("XATTR support is not available"))); done = 1; #else - static ssize_t xsz = 1024; + static size_t xsz = 1024; static char *xatrs = NULL; ssize_t xret = -1; - if (!xatrs) xatrs = xmalloc (xsz); + if (!xatrs) + xatrs = x2nrealloc (xatrs, &xsz, 1); while (((fd == 0) ? - ((xret = llistxattrat (parentfd, file_name, xatrs, xsz)) == -1) : - ((xret = flistxattr (fd, xatrs, xsz)) == -1)) && - (errno == ERANGE)) + ((xret = + llistxattrat (parentfd, file_name, xatrs, xsz)) == -1) : + ((xret = flistxattr (fd, xatrs, xsz)) == -1)) + && (errno == ERANGE)) { - xsz <<= 1; - xatrs = xrealloc (xatrs, xsz); + xatrs = x2nrealloc (xatrs, &xsz, 1); } if (xret == -1) @@ -429,10 +448,11 @@ void xattrs_xattrs_get (int parentfd, char const *file_name, else { const char *attr = xatrs; - static ssize_t asz = 1024; + static size_t asz = 1024; static char *val = NULL; - if (!val) val = xmalloc (asz); + if (!val) + val = x2nrealloc (val, &asz, 1); while (xret > 0) { @@ -447,15 +467,14 @@ void xattrs_xattrs_get (int parentfd, char const *file_name, : ((aret = fgetxattr (fd, attr, val, asz)) == -1)) && (errno == ERANGE)) { - asz <<= 1; - val = xrealloc (val, asz); + val = x2nrealloc (val, &asz, 1); } if (aret != -1) xheader_xattr_add (st, attr, val, aret); else if (errno != ENOATTR) call_arg_warn ((fd == 0) ? "lgetxattrat" - : "fgetxattr", file_name); + : "fgetxattr", file_name); attr += len + 1; xret -= len + 1; @@ -465,10 +484,11 @@ void xattrs_xattrs_get (int parentfd, char const *file_name, } } -static void xattrs__fd_set (struct tar_stat_info const *st, - char const *file_name, char typeflag, - const char *attr, - const char *ptr, size_t len) +#ifdef HAVE_XATTRS +static void +xattrs__fd_set (struct tar_stat_info const *st, + char const *file_name, char typeflag, + const char *attr, const char *ptr, size_t len) { if (ptr) { @@ -484,13 +504,78 @@ static void xattrs__fd_set (struct tar_stat_info const *st, } if (ret == -1) - WARNOPT (WARN_XATTR_WRITE, (0, errno, - _("%s: Cannot set '%s' extended attribute for file '%s'"), - sysname, attr, file_name)); + WARNOPT (WARN_XATTR_WRITE, + (0, errno, + _("%s: Cannot set '%s' extended attribute for file '%s'"), + sysname, attr, file_name)); + } +} +#endif + +/* lgetfileconat is called against FILE_NAME iff the FD parameter is set to + zero, otherwise the fgetfileconat is used against correct file descriptor */ +void +xattrs_selinux_get (int parentfd, char const *file_name, + struct tar_stat_info *st, int fd) +{ + if (selinux_context_option > 0) + { +#if HAVE_SELINUX_SELINUX_H != 1 + static int done = 0; + if (!done) + WARN ((0, 0, _("SELinux support is not available"))); + done = 1; +#else + int result = fd ? + fgetfilecon (fd, &st->cntx_name) + : lgetfileconat (parentfd, file_name, &st->cntx_name); + + if (result == -1 && errno != ENODATA && errno != ENOTSUP) + call_arg_warn (fd ? "fgetfilecon" : "lgetfileconat", file_name); +#endif + } +} + +void +xattrs_selinux_set (struct tar_stat_info const *st, + char const *file_name, char typeflag) +{ + if (selinux_context_option > 0) + { +#if HAVE_SELINUX_SELINUX_H != 1 + static int done = 0; + if (!done) + WARN ((0, 0, _("SELinux support is not available"))); + done = 1; +#else + const char *sysname = "setfilecon"; + int ret; + + if (!st->cntx_name) + return; + + if (typeflag != SYMTYPE) + { + ret = setfileconat (chdir_fd, file_name, st->cntx_name); + sysname = "setfileconat"; + } + else + { + ret = lsetfileconat (chdir_fd, file_name, st->cntx_name); + sysname = "lsetfileconat"; + } + + if (ret == -1) + WARNOPT (WARN_XATTR_WRITE, + (0, errno, + _("%s: Cannot set SELinux context for file '%s'"), + sysname, file_name)); +#endif } } -static bool xattrs_matches_mask (const char *kw, struct xattrs_mask_map *mm) +static bool +xattrs_matches_mask (const char *kw, struct xattrs_mask_map *mm) { int i; @@ -504,41 +589,39 @@ static bool xattrs_matches_mask (const char *kw, struct xattrs_mask_map *mm) return false; } -static bool xattrs_kw_included (const char *kw, bool archiving) +#define USER_DOT_PFX "user." + +static bool +xattrs_kw_included (const char *kw, bool archiving) { - if (xattrs_setup.incl.size) - return xattrs_matches_mask (kw, &xattrs_setup.incl); - else - { - if (archiving) - return true; - else - return strncmp (kw, "user.", strlen ("user.")) == 0; - } + if (xattrs_setup.incl.size) + return xattrs_matches_mask (kw, &xattrs_setup.incl); + else if (archiving) + return true; + else + return strncmp (kw, USER_DOT_PFX, sizeof (USER_DOT_PFX) - 1) == 0; } -static bool xattrs_kw_excluded (const char *kw, bool archiving) +static bool +xattrs_kw_excluded (const char *kw, bool archiving) { - if (!xattrs_setup.excl.size) - return false; - - return xattrs_matches_mask (kw, &xattrs_setup.excl); + return xattrs_setup.excl.size ? + xattrs_matches_mask (kw, &xattrs_setup.excl) : false; } /* Check whether the xattr with keyword KW should be discarded from list of attributes that are going to be archived/excluded (set ARCHIVING=true for archiving, false for excluding) */ -static bool xattrs_masked_out (const char *kw, bool archiving) +static bool +xattrs_masked_out (const char *kw, bool archiving) { - if (!xattrs_kw_included (kw, archiving)) - return true; - - return xattrs_kw_excluded (kw, archiving); + return xattrs_kw_included (kw, archiving) ? + xattrs_kw_excluded (kw, archiving) : true; } -void xattrs_xattrs_set (struct tar_stat_info const *st, - char const *file_name, char typeflag, - int later_run) +void +xattrs_xattrs_set (struct tar_stat_info const *st, + char const *file_name, char typeflag, int later_run) { if (xattrs_option > 0) { @@ -580,41 +663,52 @@ void xattrs_xattrs_set (struct tar_stat_info const *st, } } -void xattrs_print_char (struct tar_stat_info const *st, char *output) +void +xattrs_print_char (struct tar_stat_info const *st, char *output) { int i; + if (verbose_option < 2) { *output = 0; return; } - if (xattrs_option > 0 || acls_option > 0) + if (xattrs_option > 0 || selinux_context_option > 0 || acls_option > 0) { /* placeholders */ *output = ' '; - *(output + 1) = 0; + output[1] = 0; } if (xattrs_option > 0 && st->xattr_map_size) for (i = 0; i < st->xattr_map_size; ++i) { char *keyword = st->xattr_map[i].xkey + strlen ("SCHILY.xattr."); - if (xattrs_masked_out (keyword, false /* like extracting */ )) - continue; - *output = '*'; - break; + if (!xattrs_masked_out (keyword, false /* like extracting */ )) + { + *output = '*'; + break; + } } + if (selinux_context_option > 0 && st->cntx_name) + *output = '.'; + if (acls_option && (st->acls_a_len || st->acls_d_len)) *output = '+'; } -void xattrs_print (struct tar_stat_info const *st) +void +xattrs_print (struct tar_stat_info const *st) { if (verbose_option < 3) return; + /* selinux */ + if (selinux_context_option && st->cntx_name) + fprintf (stdlis, " s: %s\n", st->cntx_name); + /* acls */ if (acls_option && (st->acls_a_len || st->acls_d_len)) { @@ -628,13 +722,13 @@ void xattrs_print (struct tar_stat_info const *st) if (xattrs_option && st->xattr_map_size) { int i; + for (i = 0; i < st->xattr_map_size; ++i) { char *keyword = st->xattr_map[i].xkey + strlen ("SCHILY.xattr."); - if (xattrs_masked_out (keyword, false /* like extracting */ )) - continue; - fprintf (stdlis, " x: %lu %s\n", - (unsigned long) st->xattr_map[i].xval_len, keyword); + if (!xattrs_masked_out (keyword, false /* like extracting */ )) + fprintf (stdlis, " x: %lu %s\n", + (unsigned long) st->xattr_map[i].xval_len, keyword); } } }