1/*- 2 * Copyright (c) 2003-2010 Tim Kientzle 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer 10 * in this position and unchanged. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include "archive_platform.h" 28__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_disk.c 201159 2009-12-29 05:35:40Z kientzle $"); 29 30#ifdef HAVE_SYS_TYPES_H 31#include <sys/types.h> 32#endif 33#ifdef HAVE_SYS_ACL_H 34#define _ACL_PRIVATE /* For debugging */ 35#include <sys/acl.h> 36#endif 37#ifdef HAVE_ERRNO_H 38#include <errno.h> 39#endif 40 41#include "archive.h" 42#include "archive_entry.h" 43#include "archive_acl_private.h" 44#include "archive_write_disk_private.h" 45 46#if !defined(HAVE_POSIX_ACL) || !defined(ACL_TYPE_NFS4) 47/* Default empty function body to satisfy mainline code. */ 48int 49archive_write_disk_set_acls(struct archive *a, int fd, const char *name, 50 struct archive_acl *abstract_acl) 51{ 52 (void)a; /* UNUSED */ 53 (void)fd; /* UNUSED */ 54 (void)name; /* UNUSED */ 55 (void)abstract_acl; /* UNUSED */ 56 return (ARCHIVE_OK); 57} 58 59#else 60 61static int set_acl(struct archive *, int fd, const char *, 62 struct archive_acl *, 63 acl_type_t, int archive_entry_acl_type, const char *tn); 64 65/* 66 * XXX TODO: What about ACL types other than ACCESS and DEFAULT? 67 */ 68int 69archive_write_disk_set_acls(struct archive *a, int fd, const char *name, 70 struct archive_acl *abstract_acl) 71{ 72 int ret; 73 74 if (archive_acl_count(abstract_acl, ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) > 0) { 75 ret = set_acl(a, fd, name, abstract_acl, ACL_TYPE_ACCESS, 76 ARCHIVE_ENTRY_ACL_TYPE_ACCESS, "access"); 77 if (ret != ARCHIVE_OK) 78 return (ret); 79 ret = set_acl(a, fd, name, abstract_acl, ACL_TYPE_DEFAULT, 80 ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, "default"); 81 return (ret); 82 } else if (archive_acl_count(abstract_acl, ARCHIVE_ENTRY_ACL_TYPE_NFS4) > 0) { 83 ret = set_acl(a, fd, name, abstract_acl, ACL_TYPE_NFS4, 84 ARCHIVE_ENTRY_ACL_TYPE_NFS4, "nfs4"); 85 return (ret); 86 } else 87 return ARCHIVE_OK; 88} 89 90static struct { 91 int archive_perm; 92 int platform_perm; 93} acl_perm_map[] = { 94 {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE}, 95 {ARCHIVE_ENTRY_ACL_WRITE, ACL_WRITE}, 96 {ARCHIVE_ENTRY_ACL_READ, ACL_READ}, 97 {ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA}, 98 {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY}, 99 {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA}, 100 {ARCHIVE_ENTRY_ACL_ADD_FILE, ACL_ADD_FILE}, 101 {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACL_APPEND_DATA}, 102 {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACL_ADD_SUBDIRECTORY}, 103 {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACL_READ_NAMED_ATTRS}, 104 {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACL_WRITE_NAMED_ATTRS}, 105 {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACL_DELETE_CHILD}, 106 {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES}, 107 {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES}, 108 {ARCHIVE_ENTRY_ACL_DELETE, ACL_DELETE}, 109 {ARCHIVE_ENTRY_ACL_READ_ACL, ACL_READ_ACL}, 110 {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_ACL}, 111 {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_WRITE_OWNER}, 112 {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE} 113}; 114 115static struct { 116 int archive_inherit; 117 int platform_inherit; 118} acl_inherit_map[] = { 119 {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT}, 120 {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT}, 121 {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_NO_PROPAGATE_INHERIT}, 122 {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_INHERIT_ONLY} 123}; 124 125static int 126set_acl(struct archive *a, int fd, const char *name, 127 struct archive_acl *abstract_acl, 128 acl_type_t acl_type, int ae_requested_type, const char *tname) 129{ 130 acl_t acl; 131 acl_entry_t acl_entry; 132 acl_permset_t acl_permset; 133 acl_flagset_t acl_flagset; 134 int r; 135 int ret; 136 int ae_type, ae_permset, ae_tag, ae_id; 137 uid_t ae_uid; 138 gid_t ae_gid; 139 const char *ae_name; 140 int entries; 141 int i; 142 143 ret = ARCHIVE_OK; 144 entries = archive_acl_reset(abstract_acl, ae_requested_type); 145 if (entries == 0) 146 return (ARCHIVE_OK); 147 acl = acl_init(entries); 148 if (acl == (acl_t)NULL) { 149 archive_set_error(a, errno, 150 "Failed to initialize ACL working storage"); 151 return (ARCHIVE_FAILED); 152 } 153 while (archive_acl_next(a, abstract_acl, ae_requested_type, &ae_type, 154 &ae_permset, &ae_tag, &ae_id, &ae_name) == ARCHIVE_OK) { 155 if (acl_create_entry(&acl, &acl_entry) != 0) { 156 archive_set_error(a, errno, 157 "Failed to create a new ACL entry"); 158 ret = ARCHIVE_FAILED; 159 goto exit_free; 160 } 161 162 switch (ae_tag) { 163 case ARCHIVE_ENTRY_ACL_USER: 164 acl_set_tag_type(acl_entry, ACL_USER); 165 ae_uid = archive_write_disk_uid(a, ae_name, ae_id); 166 acl_set_qualifier(acl_entry, &ae_uid); 167 break; 168 case ARCHIVE_ENTRY_ACL_GROUP: 169 acl_set_tag_type(acl_entry, ACL_GROUP); 170 ae_gid = archive_write_disk_gid(a, ae_name, ae_id); 171 acl_set_qualifier(acl_entry, &ae_gid); 172 break; 173 case ARCHIVE_ENTRY_ACL_USER_OBJ: 174 acl_set_tag_type(acl_entry, ACL_USER_OBJ); 175 break; 176 case ARCHIVE_ENTRY_ACL_GROUP_OBJ: 177 acl_set_tag_type(acl_entry, ACL_GROUP_OBJ); 178 break; 179 case ARCHIVE_ENTRY_ACL_MASK: 180 acl_set_tag_type(acl_entry, ACL_MASK); 181 break; 182 case ARCHIVE_ENTRY_ACL_OTHER: 183 acl_set_tag_type(acl_entry, ACL_OTHER); 184 break; 185 case ARCHIVE_ENTRY_ACL_EVERYONE: 186 acl_set_tag_type(acl_entry, ACL_EVERYONE); 187 break; 188 default: 189 archive_set_error(a, ARCHIVE_ERRNO_MISC, 190 "Unknown ACL tag"); 191 ret = ARCHIVE_FAILED; 192 goto exit_free; 193 } 194 195 r = 0; 196 switch (ae_type) { 197 case ARCHIVE_ENTRY_ACL_TYPE_ALLOW: 198 r = acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_ALLOW); 199 break; 200 case ARCHIVE_ENTRY_ACL_TYPE_DENY: 201 r = acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_DENY); 202 break; 203 case ARCHIVE_ENTRY_ACL_TYPE_AUDIT: 204 r = acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_AUDIT); 205 break; 206 case ARCHIVE_ENTRY_ACL_TYPE_ALARM: 207 r = acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_ALARM); 208 break; 209 case ARCHIVE_ENTRY_ACL_TYPE_ACCESS: 210 case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT: 211 // These don't translate directly into the system ACL. 212 break; 213 default: 214 archive_set_error(a, ARCHIVE_ERRNO_MISC, 215 "Unknown ACL entry type"); 216 ret = ARCHIVE_FAILED; 217 goto exit_free; 218 } 219 if (r != 0) { 220 archive_set_error(a, errno, 221 "Failed to set ACL entry type"); 222 ret = ARCHIVE_FAILED; 223 goto exit_free; 224 } 225 226 if (acl_get_permset(acl_entry, &acl_permset) != 0) { 227 archive_set_error(a, errno, 228 "Failed to get ACL permission set"); 229 ret = ARCHIVE_FAILED; 230 goto exit_free; 231 } 232 if (acl_clear_perms(acl_permset) != 0) { 233 archive_set_error(a, errno, 234 "Failed to clear ACL permissions"); 235 ret = ARCHIVE_FAILED; 236 goto exit_free; 237 } 238 239 for (i = 0; i < (int)(sizeof(acl_perm_map) / sizeof(acl_perm_map[0])); ++i) { 240 if (ae_permset & acl_perm_map[i].archive_perm) 241 if (acl_add_perm(acl_permset, 242 acl_perm_map[i].platform_perm) != 0) { 243 archive_set_error(a, errno, 244 "Failed to add ACL permission"); 245 ret = ARCHIVE_FAILED; 246 goto exit_free; 247 } 248 } 249 250 acl_get_flagset_np(acl_entry, &acl_flagset); 251 if (acl_type == ACL_TYPE_NFS4) { 252 /* 253 * acl_get_flagset_np() fails with non-NFSv4 ACLs 254 */ 255 if (acl_get_flagset_np(acl_entry, &acl_flagset) != 0) { 256 archive_set_error(a, errno, 257 "Failed to get flagset from an NFSv4 ACL entry"); 258 ret = ARCHIVE_FAILED; 259 goto exit_free; 260 } 261 if (acl_clear_flags_np(acl_flagset) != 0) { 262 archive_set_error(a, errno, 263 "Failed to clear flags from an NFSv4 ACL flagset"); 264 ret = ARCHIVE_FAILED; 265 goto exit_free; 266 } 267 for (i = 0; i < (int)(sizeof(acl_inherit_map) / sizeof(acl_inherit_map[0])); ++i) { 268 if (ae_permset & acl_inherit_map[i].archive_inherit) { 269 if (acl_add_flag_np(acl_flagset, 270 acl_inherit_map[i].platform_inherit) != 0) { 271 archive_set_error(a, errno, 272 "Failed to add flag to NFSv4 ACL flagset"); 273 ret = ARCHIVE_FAILED; 274 goto exit_free; 275 } 276 } 277 } 278 } 279 } 280 281 /* Try restoring the ACL through 'fd' if we can. */ 282#if HAVE_ACL_SET_FD 283 if (fd >= 0 && acl_type == ACL_TYPE_ACCESS && acl_set_fd(fd, acl) == 0) 284 ret = ARCHIVE_OK; 285 else 286#else 287#if HAVE_ACL_SET_FD_NP 288 if (fd >= 0 && acl_set_fd_np(fd, acl, acl_type) == 0) 289 ret = ARCHIVE_OK; 290 else 291#endif 292#endif 293#if HAVE_ACL_SET_LINK_NP 294 if (acl_set_link_np(name, acl_type, acl) != 0) { 295 archive_set_error(a, errno, "Failed to set %s acl", tname); 296 ret = ARCHIVE_WARN; 297 } 298#else 299 /* TODO: Skip this if 'name' is a symlink. */ 300 if (acl_set_file(name, acl_type, acl) != 0) { 301 archive_set_error(a, errno, "Failed to set %s acl", tname); 302 ret = ARCHIVE_WARN; 303 } 304#endif 305exit_free: 306 acl_free(acl); 307 return (ret); 308} 309#endif 310