archive_disk_acl_freebsd.c revision 316338
1/*- 2 * Copyright (c) 2003-2009 Tim Kientzle 3 * Copyright (c) 2010-2012 Michihiro NAKAJIMA 4 * Copyright (c) 2017 Martin Matuska 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28#include "archive_platform.h" 29 30#if ARCHIVE_ACL_FREEBSD 31 32#ifdef HAVE_ERRNO_H 33#include <errno.h> 34#endif 35#ifdef HAVE_FCNTL_H 36#include <fcntl.h> 37#endif 38#ifdef HAVE_SYS_TYPES_H 39#include <sys/types.h> 40#endif 41#ifdef HAVE_SYS_ACL_H 42#define _ACL_PRIVATE /* For debugging */ 43#include <sys/acl.h> 44#endif 45 46#include "archive_entry.h" 47#include "archive_private.h" 48#include "archive_read_disk_private.h" 49#include "archive_write_disk_private.h" 50 51typedef struct { 52 const int a_perm; /* Libarchive permission or flag */ 53 const int p_perm; /* Platform permission or flag */ 54} acl_perm_map_t; 55 56static const acl_perm_map_t acl_posix_perm_map[] = { 57 {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE}, 58 {ARCHIVE_ENTRY_ACL_WRITE, ACL_WRITE}, 59 {ARCHIVE_ENTRY_ACL_READ, ACL_READ}, 60}; 61 62static const int acl_posix_perm_map_size = 63 (int)(sizeof(acl_posix_perm_map)/sizeof(acl_posix_perm_map[0])); 64 65#if ARCHIVE_ACL_FREEBSD_NFS4 66static const acl_perm_map_t acl_nfs4_perm_map[] = { 67 {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE}, 68 {ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA}, 69 {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY}, 70 {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA}, 71 {ARCHIVE_ENTRY_ACL_ADD_FILE, ACL_ADD_FILE}, 72 {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACL_APPEND_DATA}, 73 {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACL_ADD_SUBDIRECTORY}, 74 {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACL_READ_NAMED_ATTRS}, 75 {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACL_WRITE_NAMED_ATTRS}, 76 {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACL_DELETE_CHILD}, 77 {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES}, 78 {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES}, 79 {ARCHIVE_ENTRY_ACL_DELETE, ACL_DELETE}, 80 {ARCHIVE_ENTRY_ACL_READ_ACL, ACL_READ_ACL}, 81 {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_ACL}, 82 {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_WRITE_OWNER}, 83 {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE} 84}; 85 86static const int acl_nfs4_perm_map_size = 87 (int)(sizeof(acl_nfs4_perm_map)/sizeof(acl_nfs4_perm_map[0])); 88 89static const acl_perm_map_t acl_nfs4_flag_map[] = { 90 {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT}, 91 {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT}, 92 {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_NO_PROPAGATE_INHERIT}, 93 {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_INHERIT_ONLY}, 94 {ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, ACL_ENTRY_SUCCESSFUL_ACCESS}, 95 {ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, ACL_ENTRY_FAILED_ACCESS}, 96 {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACL_ENTRY_INHERITED} 97}; 98 99static const int acl_nfs4_flag_map_size = 100 (int)(sizeof(acl_nfs4_flag_map)/sizeof(acl_nfs4_flag_map[0])); 101#endif /* ARCHIVE_ACL_FREEBSD_NFS4 */ 102 103static int 104translate_acl(struct archive_read_disk *a, 105 struct archive_entry *entry, acl_t acl, int default_entry_acl_type) 106{ 107#if ARCHIVE_ACL_FREEBSD_NFS4 108 int brand; 109 acl_flagset_t acl_flagset; 110 acl_entry_type_t acl_type; 111#endif 112 acl_tag_t acl_tag; 113 acl_entry_t acl_entry; 114 acl_permset_t acl_permset; 115 int i, entry_acl_type, perm_map_size; 116 const acl_perm_map_t *perm_map; 117 int r, s, ae_id, ae_tag, ae_perm; 118 void *q; 119 const char *ae_name; 120 121#if ARCHIVE_ACL_FREEBSD_NFS4 122 // FreeBSD "brands" ACLs as POSIX.1e or NFSv4 123 // Make sure the "brand" on this ACL is consistent 124 // with the default_entry_acl_type bits provided. 125 if (acl_get_brand_np(acl, &brand) != 0) { 126 archive_set_error(&a->archive, errno, 127 "Failed to read ACL brand"); 128 return (ARCHIVE_WARN); 129 } 130 switch (brand) { 131 case ACL_BRAND_POSIX: 132 switch (default_entry_acl_type) { 133 case ARCHIVE_ENTRY_ACL_TYPE_ACCESS: 134 case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT: 135 break; 136 default: 137 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 138 "Invalid ACL entry type for POSIX.1e ACL"); 139 return (ARCHIVE_WARN); 140 } 141 break; 142 case ACL_BRAND_NFS4: 143 if (default_entry_acl_type & ~ARCHIVE_ENTRY_ACL_TYPE_NFS4) { 144 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 145 "Invalid ACL entry type for NFSv4 ACL"); 146 return (ARCHIVE_WARN); 147 } 148 break; 149 default: 150 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 151 "Unknown ACL brand"); 152 return (ARCHIVE_WARN); 153 } 154#endif 155 156 s = acl_get_entry(acl, ACL_FIRST_ENTRY, &acl_entry); 157 if (s == -1) { 158 archive_set_error(&a->archive, errno, 159 "Failed to get first ACL entry"); 160 return (ARCHIVE_WARN); 161 } 162 163 while (s == 1) { 164 ae_id = -1; 165 ae_name = NULL; 166 ae_perm = 0; 167 168 if (acl_get_tag_type(acl_entry, &acl_tag) != 0) { 169 archive_set_error(&a->archive, errno, 170 "Failed to get ACL tag type"); 171 return (ARCHIVE_WARN); 172 } 173 switch (acl_tag) { 174 case ACL_USER: 175 q = acl_get_qualifier(acl_entry); 176 if (q != NULL) { 177 ae_id = (int)*(uid_t *)q; 178 acl_free(q); 179 ae_name = archive_read_disk_uname(&a->archive, 180 ae_id); 181 } 182 ae_tag = ARCHIVE_ENTRY_ACL_USER; 183 break; 184 case ACL_GROUP: 185 q = acl_get_qualifier(acl_entry); 186 if (q != NULL) { 187 ae_id = (int)*(gid_t *)q; 188 acl_free(q); 189 ae_name = archive_read_disk_gname(&a->archive, 190 ae_id); 191 } 192 ae_tag = ARCHIVE_ENTRY_ACL_GROUP; 193 break; 194 case ACL_MASK: 195 ae_tag = ARCHIVE_ENTRY_ACL_MASK; 196 break; 197 case ACL_USER_OBJ: 198 ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ; 199 break; 200 case ACL_GROUP_OBJ: 201 ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; 202 break; 203 case ACL_OTHER: 204 ae_tag = ARCHIVE_ENTRY_ACL_OTHER; 205 break; 206#if ARCHIVE_ACL_FREEBSD_NFS4 207 case ACL_EVERYONE: 208 ae_tag = ARCHIVE_ENTRY_ACL_EVERYONE; 209 break; 210#endif 211 default: 212 /* Skip types that libarchive can't support. */ 213 s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry); 214 continue; 215 } 216 217 // XXX acl_type maps to allow/deny/audit/YYYY bits 218 entry_acl_type = default_entry_acl_type; 219 220#if ARCHIVE_ACL_FREEBSD_NFS4 221 if (default_entry_acl_type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) { 222 /* 223 * acl_get_entry_type_np() fails with non-NFSv4 ACLs 224 */ 225 if (acl_get_entry_type_np(acl_entry, &acl_type) != 0) { 226 archive_set_error(&a->archive, errno, "Failed " 227 "to get ACL type from a NFSv4 ACL entry"); 228 return (ARCHIVE_WARN); 229 } 230 switch (acl_type) { 231 case ACL_ENTRY_TYPE_ALLOW: 232 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW; 233 break; 234 case ACL_ENTRY_TYPE_DENY: 235 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DENY; 236 break; 237 case ACL_ENTRY_TYPE_AUDIT: 238 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_AUDIT; 239 break; 240 case ACL_ENTRY_TYPE_ALARM: 241 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALARM; 242 break; 243 default: 244 archive_set_error(&a->archive, errno, 245 "Invalid NFSv4 ACL entry type"); 246 return (ARCHIVE_WARN); 247 } 248 249 /* 250 * Libarchive stores "flag" (NFSv4 inheritance bits) 251 * in the ae_perm bitmap. 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->archive, errno, 257 "Failed to get flagset from a NFSv4 " 258 "ACL entry"); 259 return (ARCHIVE_WARN); 260 } 261 for (i = 0; i < acl_nfs4_flag_map_size; ++i) { 262 r = acl_get_flag_np(acl_flagset, 263 acl_nfs4_flag_map[i].p_perm); 264 if (r == -1) { 265 archive_set_error(&a->archive, errno, 266 "Failed to check flag in a NFSv4 " 267 "ACL flagset"); 268 return (ARCHIVE_WARN); 269 } else if (r) 270 ae_perm |= acl_nfs4_flag_map[i].a_perm; 271 } 272 } 273#endif 274 275 if (acl_get_permset(acl_entry, &acl_permset) != 0) { 276 archive_set_error(&a->archive, errno, 277 "Failed to get ACL permission set"); 278 return (ARCHIVE_WARN); 279 } 280 281#if ARCHIVE_ACL_FREEBSD_NFS4 282 if (default_entry_acl_type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) { 283 perm_map_size = acl_nfs4_perm_map_size; 284 perm_map = acl_nfs4_perm_map; 285 } else { 286#endif 287 perm_map_size = acl_posix_perm_map_size; 288 perm_map = acl_posix_perm_map; 289#if ARCHIVE_ACL_FREEBSD_NFS4 290 } 291#endif 292 293 for (i = 0; i < perm_map_size; ++i) { 294 r = acl_get_perm_np(acl_permset, perm_map[i].p_perm); 295 if (r == -1) { 296 archive_set_error(&a->archive, errno, 297 "Failed to check permission in an ACL " 298 "permission set"); 299 return (ARCHIVE_WARN); 300 } else if (r) 301 ae_perm |= perm_map[i].a_perm; 302 } 303 304 archive_entry_acl_add_entry(entry, entry_acl_type, 305 ae_perm, ae_tag, 306 ae_id, ae_name); 307 308 s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry); 309 if (s == -1) { 310 archive_set_error(&a->archive, errno, 311 "Failed to get next ACL entry"); 312 return (ARCHIVE_WARN); 313 } 314 } 315 return (ARCHIVE_OK); 316} 317 318static int 319set_acl(struct archive *a, int fd, const char *name, 320 struct archive_acl *abstract_acl, 321 int ae_requested_type, const char *tname) 322{ 323 int acl_type = 0; 324 acl_t acl; 325 acl_entry_t acl_entry; 326 acl_permset_t acl_permset; 327#if ARCHIVE_ACL_FREEBSD_NFS4 328 acl_flagset_t acl_flagset; 329 int r; 330#endif 331 int ret; 332 int ae_type, ae_permset, ae_tag, ae_id; 333 int perm_map_size; 334 const acl_perm_map_t *perm_map; 335 uid_t ae_uid; 336 gid_t ae_gid; 337 const char *ae_name; 338 int entries; 339 int i; 340 341 ret = ARCHIVE_OK; 342 entries = archive_acl_reset(abstract_acl, ae_requested_type); 343 if (entries == 0) 344 return (ARCHIVE_OK); 345 346 347 switch (ae_requested_type) { 348 case ARCHIVE_ENTRY_ACL_TYPE_ACCESS: 349 acl_type = ACL_TYPE_ACCESS; 350 break; 351 case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT: 352 acl_type = ACL_TYPE_DEFAULT; 353 break; 354#if ARCHIVE_ACL_FREEBSD_NFS4 355 case ARCHIVE_ENTRY_ACL_TYPE_NFS4: 356 acl_type = ACL_TYPE_NFS4; 357 break; 358#endif 359 default: 360 errno = ENOENT; 361 archive_set_error(a, errno, "Unsupported ACL type"); 362 return (ARCHIVE_FAILED); 363 } 364 365 acl = acl_init(entries); 366 if (acl == (acl_t)NULL) { 367 archive_set_error(a, errno, 368 "Failed to initialize ACL working storage"); 369 return (ARCHIVE_FAILED); 370 } 371 372 while (archive_acl_next(a, abstract_acl, ae_requested_type, &ae_type, 373 &ae_permset, &ae_tag, &ae_id, &ae_name) == ARCHIVE_OK) { 374 if (acl_create_entry(&acl, &acl_entry) != 0) { 375 archive_set_error(a, errno, 376 "Failed to create a new ACL entry"); 377 ret = ARCHIVE_FAILED; 378 goto exit_free; 379 } 380 switch (ae_tag) { 381 case ARCHIVE_ENTRY_ACL_USER: 382 ae_uid = archive_write_disk_uid(a, ae_name, ae_id); 383 acl_set_tag_type(acl_entry, ACL_USER); 384 acl_set_qualifier(acl_entry, &ae_uid); 385 break; 386 case ARCHIVE_ENTRY_ACL_GROUP: 387 ae_gid = archive_write_disk_gid(a, ae_name, ae_id); 388 acl_set_tag_type(acl_entry, ACL_GROUP); 389 acl_set_qualifier(acl_entry, &ae_gid); 390 break; 391 case ARCHIVE_ENTRY_ACL_USER_OBJ: 392 acl_set_tag_type(acl_entry, ACL_USER_OBJ); 393 break; 394 case ARCHIVE_ENTRY_ACL_GROUP_OBJ: 395 acl_set_tag_type(acl_entry, ACL_GROUP_OBJ); 396 break; 397 case ARCHIVE_ENTRY_ACL_MASK: 398 acl_set_tag_type(acl_entry, ACL_MASK); 399 break; 400 case ARCHIVE_ENTRY_ACL_OTHER: 401 acl_set_tag_type(acl_entry, ACL_OTHER); 402 break; 403#if ARCHIVE_ACL_FREEBSD_NFS4 404 case ARCHIVE_ENTRY_ACL_EVERYONE: 405 acl_set_tag_type(acl_entry, ACL_EVERYONE); 406 break; 407#endif 408 default: 409 archive_set_error(a, ARCHIVE_ERRNO_MISC, 410 "Unsupported ACL tag"); 411 ret = ARCHIVE_FAILED; 412 goto exit_free; 413 } 414 415#if ARCHIVE_ACL_FREEBSD_NFS4 416 r = 0; 417 switch (ae_type) { 418 case ARCHIVE_ENTRY_ACL_TYPE_ALLOW: 419 r = acl_set_entry_type_np(acl_entry, 420 ACL_ENTRY_TYPE_ALLOW); 421 break; 422 case ARCHIVE_ENTRY_ACL_TYPE_DENY: 423 r = acl_set_entry_type_np(acl_entry, 424 ACL_ENTRY_TYPE_DENY); 425 break; 426 case ARCHIVE_ENTRY_ACL_TYPE_AUDIT: 427 r = acl_set_entry_type_np(acl_entry, 428 ACL_ENTRY_TYPE_AUDIT); 429 break; 430 case ARCHIVE_ENTRY_ACL_TYPE_ALARM: 431 r = acl_set_entry_type_np(acl_entry, 432 ACL_ENTRY_TYPE_ALARM); 433 break; 434 case ARCHIVE_ENTRY_ACL_TYPE_ACCESS: 435 case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT: 436 // These don't translate directly into the system ACL. 437 break; 438 default: 439 archive_set_error(a, ARCHIVE_ERRNO_MISC, 440 "Unsupported ACL entry type"); 441 ret = ARCHIVE_FAILED; 442 goto exit_free; 443 } 444 445 if (r != 0) { 446 archive_set_error(a, errno, 447 "Failed to set ACL entry type"); 448 ret = ARCHIVE_FAILED; 449 goto exit_free; 450 } 451#endif 452 453 if (acl_get_permset(acl_entry, &acl_permset) != 0) { 454 archive_set_error(a, errno, 455 "Failed to get ACL permission set"); 456 ret = ARCHIVE_FAILED; 457 goto exit_free; 458 } 459 if (acl_clear_perms(acl_permset) != 0) { 460 archive_set_error(a, errno, 461 "Failed to clear ACL permissions"); 462 ret = ARCHIVE_FAILED; 463 goto exit_free; 464 } 465#if ARCHIVE_ACL_FREEBSD_NFS4 466 if (ae_requested_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) { 467 perm_map_size = acl_nfs4_perm_map_size; 468 perm_map = acl_nfs4_perm_map; 469 } else { 470#endif 471 perm_map_size = acl_posix_perm_map_size; 472 perm_map = acl_posix_perm_map; 473#if ARCHIVE_ACL_FREEBSD_NFS4 474 } 475#endif 476 477 for (i = 0; i < perm_map_size; ++i) { 478 if (ae_permset & perm_map[i].a_perm) { 479 if (acl_add_perm(acl_permset, 480 perm_map[i].p_perm) != 0) { 481 archive_set_error(a, errno, 482 "Failed to add ACL permission"); 483 ret = ARCHIVE_FAILED; 484 goto exit_free; 485 } 486 } 487 } 488 489#if ARCHIVE_ACL_FREEBSD_NFS4 490 if (ae_requested_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) { 491 /* 492 * acl_get_flagset_np() fails with non-NFSv4 ACLs 493 */ 494 if (acl_get_flagset_np(acl_entry, &acl_flagset) != 0) { 495 archive_set_error(a, errno, 496 "Failed to get flagset from an NFSv4 " 497 "ACL entry"); 498 ret = ARCHIVE_FAILED; 499 goto exit_free; 500 } 501 if (acl_clear_flags_np(acl_flagset) != 0) { 502 archive_set_error(a, errno, 503 "Failed to clear flags from an NFSv4 " 504 "ACL flagset"); 505 ret = ARCHIVE_FAILED; 506 goto exit_free; 507 } 508 for (i = 0; i < acl_nfs4_flag_map_size; ++i) { 509 if (ae_permset & acl_nfs4_flag_map[i].a_perm) { 510 if (acl_add_flag_np(acl_flagset, 511 acl_nfs4_flag_map[i].p_perm) != 0) { 512 archive_set_error(a, errno, 513 "Failed to add flag to " 514 "NFSv4 ACL flagset"); 515 ret = ARCHIVE_FAILED; 516 goto exit_free; 517 } 518 } 519 } 520 } 521#endif 522 } 523 524 /* Try restoring the ACL through 'fd' if we can. */ 525 if (fd >= 0) { 526 if (acl_set_fd_np(fd, acl, acl_type) == 0) 527 ret = ARCHIVE_OK; 528 else { 529 if (errno == EOPNOTSUPP) { 530 /* Filesystem doesn't support ACLs */ 531 ret = ARCHIVE_OK; 532 } else { 533 archive_set_error(a, errno, 534 "Failed to set acl on fd: %s", tname); 535 ret = ARCHIVE_WARN; 536 } 537 } 538 } 539#if HAVE_ACL_SET_LINK_NP 540 else if (acl_set_link_np(name, acl_type, acl) != 0) 541#else 542 /* FreeBSD older than 8.0 */ 543 else if (acl_set_file(name, acl_type, acl) != 0) 544#endif 545 { 546 if (errno == EOPNOTSUPP) { 547 /* Filesystem doesn't support ACLs */ 548 ret = ARCHIVE_OK; 549 } else { 550 archive_set_error(a, errno, "Failed to set acl: %s", 551 tname); 552 ret = ARCHIVE_WARN; 553 } 554 } 555exit_free: 556 acl_free(acl); 557 return (ret); 558} 559 560int 561archive_read_disk_entry_setup_acls(struct archive_read_disk *a, 562 struct archive_entry *entry, int *fd) 563{ 564 const char *accpath; 565 acl_t acl; 566 int r; 567 568 accpath = NULL; 569 570 if (*fd < 0) { 571 accpath = archive_read_disk_entry_setup_path(a, entry, fd); 572 if (accpath == NULL) 573 return (ARCHIVE_WARN); 574 } 575 576 archive_entry_acl_clear(entry); 577 578 acl = NULL; 579 580#if ARCHIVE_ACL_FREEBSD_NFS4 581 /* Try NFSv4 ACL first. */ 582 if (*fd >= 0) 583 acl = acl_get_fd_np(*fd, ACL_TYPE_NFS4); 584 else if (!a->follow_symlinks) 585 acl = acl_get_link_np(accpath, ACL_TYPE_NFS4); 586 else 587 acl = acl_get_file(accpath, ACL_TYPE_NFS4); 588 589 /* Ignore "trivial" ACLs that just mirror the file mode. */ 590 if (acl != NULL && acl_is_trivial_np(acl, &r) == 0 && r == 1) { 591 acl_free(acl); 592 acl = NULL; 593 return (ARCHIVE_OK); 594 } 595 596 if (acl != NULL) { 597 r = translate_acl(a, entry, acl, ARCHIVE_ENTRY_ACL_TYPE_NFS4); 598 acl_free(acl); 599 acl = NULL; 600 601 if (r != ARCHIVE_OK) { 602 archive_set_error(&a->archive, errno, 603 "Couldn't translate NFSv4 ACLs"); 604 } 605 606 return (r); 607 } 608#endif 609 610 /* Retrieve access ACL from file. */ 611 if (*fd >= 0) 612 acl = acl_get_fd_np(*fd, ACL_TYPE_ACCESS); 613#if HAVE_ACL_GET_LINK_NP 614 else if (!a->follow_symlinks) 615 acl = acl_get_link_np(accpath, ACL_TYPE_ACCESS); 616#else 617 else if ((!a->follow_symlinks) 618 && (archive_entry_filetype(entry) == AE_IFLNK)) 619 /* We can't get the ACL of a symlink, so we assume it can't 620 have one. */ 621 acl = NULL; 622#endif 623 else 624 acl = acl_get_file(accpath, ACL_TYPE_ACCESS); 625 626#if HAVE_ACL_IS_TRIVIAL_NP 627 /* Ignore "trivial" ACLs that just mirror the file mode. */ 628 if (acl != NULL && acl_is_trivial_np(acl, &r) == 0 && r == 1) { 629 acl_free(acl); 630 acl = NULL; 631 } 632#endif 633 634 if (acl != NULL) { 635 r = translate_acl(a, entry, acl, ARCHIVE_ENTRY_ACL_TYPE_ACCESS); 636 acl_free(acl); 637 acl = NULL; 638 639 if (r != ARCHIVE_OK) { 640 archive_set_error(&a->archive, errno, 641 "Couldn't translate access ACLs"); 642 return (r); 643 } 644 } 645 646 /* Only directories can have default ACLs. */ 647 if (S_ISDIR(archive_entry_mode(entry))) { 648 if (*fd >= 0) 649 acl = acl_get_fd_np(*fd, ACL_TYPE_DEFAULT); 650 else 651 acl = acl_get_file(accpath, ACL_TYPE_DEFAULT); 652 if (acl != NULL) { 653 r = translate_acl(a, entry, acl, 654 ARCHIVE_ENTRY_ACL_TYPE_DEFAULT); 655 acl_free(acl); 656 if (r != ARCHIVE_OK) { 657 archive_set_error(&a->archive, errno, 658 "Couldn't translate default ACLs"); 659 return (r); 660 } 661 } 662 } 663 return (ARCHIVE_OK); 664} 665 666int 667archive_write_disk_set_acls(struct archive *a, int fd, const char *name, 668 struct archive_acl *abstract_acl, __LA_MODE_T mode) 669{ 670 int ret = ARCHIVE_OK; 671 672 (void)mode; /* UNUSED */ 673 674 if ((archive_acl_types(abstract_acl) 675 & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) { 676 if ((archive_acl_types(abstract_acl) 677 & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) { 678 ret = set_acl(a, fd, name, abstract_acl, 679 ARCHIVE_ENTRY_ACL_TYPE_ACCESS, "access"); 680 if (ret != ARCHIVE_OK) 681 return (ret); 682 } 683 if ((archive_acl_types(abstract_acl) 684 & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) 685 ret = set_acl(a, fd, name, abstract_acl, 686 ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, "default"); 687 688 /* Simultaneous POSIX.1e and NFSv4 is not supported */ 689 return (ret); 690 } 691#if ARCHIVE_ACL_FREEBSD_NFS4 692 else if ((archive_acl_types(abstract_acl) & 693 ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) { 694 ret = set_acl(a, fd, name, abstract_acl, 695 ARCHIVE_ENTRY_ACL_TYPE_NFS4, "nfs4"); 696 } 697#endif 698 return (ret); 699} 700#endif /* ARCHIVE_ACL_FREEBSD */ 701