1/*- 2 * Copyright (c) 2017 Martin Matuska 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 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "archive_platform.h" 27 28#if ARCHIVE_ACL_SUNOS 29 30#ifdef HAVE_ERRNO_H 31#include <errno.h> 32#endif 33#ifdef HAVE_FCNTL_H 34#include <fcntl.h> 35#endif 36#ifdef HAVE_SYS_TYPES_H 37#include <sys/types.h> 38#endif 39#ifdef HAVE_SYS_ACL_H 40#define _ACL_PRIVATE /* For debugging */ 41#include <sys/acl.h> 42#endif 43 44#include "archive_entry.h" 45#include "archive_private.h" 46#include "archive_read_disk_private.h" 47#include "archive_write_disk_private.h" 48 49typedef struct { 50 const int a_perm; /* Libarchive permission or flag */ 51 const int p_perm; /* Platform permission or flag */ 52} acl_perm_map_t; 53 54static const acl_perm_map_t acl_posix_perm_map[] = { 55 {ARCHIVE_ENTRY_ACL_EXECUTE, S_IXOTH }, 56 {ARCHIVE_ENTRY_ACL_WRITE, S_IWOTH }, 57 {ARCHIVE_ENTRY_ACL_READ, S_IROTH } 58}; 59 60static const int acl_posix_perm_map_size = 61 (int)(sizeof(acl_posix_perm_map)/sizeof(acl_posix_perm_map[0])); 62 63#if ARCHIVE_ACL_SUNOS_NFS4 64static const acl_perm_map_t acl_nfs4_perm_map[] = { 65 {ARCHIVE_ENTRY_ACL_EXECUTE, ACE_EXECUTE}, 66 {ARCHIVE_ENTRY_ACL_READ_DATA, ACE_READ_DATA}, 67 {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACE_LIST_DIRECTORY}, 68 {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACE_WRITE_DATA}, 69 {ARCHIVE_ENTRY_ACL_ADD_FILE, ACE_ADD_FILE}, 70 {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACE_APPEND_DATA}, 71 {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACE_ADD_SUBDIRECTORY}, 72 {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACE_READ_NAMED_ATTRS}, 73 {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACE_WRITE_NAMED_ATTRS}, 74 {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACE_DELETE_CHILD}, 75 {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACE_READ_ATTRIBUTES}, 76 {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACE_WRITE_ATTRIBUTES}, 77 {ARCHIVE_ENTRY_ACL_DELETE, ACE_DELETE}, 78 {ARCHIVE_ENTRY_ACL_READ_ACL, ACE_READ_ACL}, 79 {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACE_WRITE_ACL}, 80 {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACE_WRITE_OWNER}, 81 {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACE_SYNCHRONIZE} 82}; 83 84static const int acl_nfs4_perm_map_size = 85 (int)(sizeof(acl_nfs4_perm_map)/sizeof(acl_nfs4_perm_map[0])); 86 87static const acl_perm_map_t acl_nfs4_flag_map[] = { 88 {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACE_FILE_INHERIT_ACE}, 89 {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACE_DIRECTORY_INHERIT_ACE}, 90 {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACE_NO_PROPAGATE_INHERIT_ACE}, 91 {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACE_INHERIT_ONLY_ACE}, 92 {ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, ACE_SUCCESSFUL_ACCESS_ACE_FLAG}, 93 {ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, ACE_FAILED_ACCESS_ACE_FLAG}, 94#ifdef ACE_INHERITED_ACE 95 {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACE_INHERITED_ACE} 96#endif 97}; 98 99const int acl_nfs4_flag_map_size = 100 (int)(sizeof(acl_nfs4_flag_map)/sizeof(acl_nfs4_flag_map[0])); 101 102#endif /* ARCHIVE_ACL_SUNOS_NFS4 */ 103 104static void * 105sunacl_get(int cmd, int *aclcnt, int fd, const char *path) 106{ 107 int cnt, cntcmd; 108 size_t size; 109 void *aclp; 110 111 if (cmd == GETACL) { 112 cntcmd = GETACLCNT; 113 size = sizeof(aclent_t); 114 } 115#if ARCHIVE_ACL_SUNOS_NFS4 116 else if (cmd == ACE_GETACL) { 117 cntcmd = ACE_GETACLCNT; 118 size = sizeof(ace_t); 119 } 120#endif 121 else { 122 errno = EINVAL; 123 *aclcnt = -1; 124 return (NULL); 125 } 126 127 aclp = NULL; 128 cnt = -2; 129 130 while (cnt == -2 || (cnt == -1 && errno == ENOSPC)) { 131 if (path != NULL) 132 cnt = acl(path, cntcmd, 0, NULL); 133 else 134 cnt = facl(fd, cntcmd, 0, NULL); 135 136 if (cnt > 0) { 137 if (aclp == NULL) 138 aclp = malloc(cnt * size); 139 else 140 aclp = realloc(NULL, cnt * size); 141 if (aclp != NULL) { 142 if (path != NULL) 143 cnt = acl(path, cmd, cnt, aclp); 144 else 145 cnt = facl(fd, cmd, cnt, aclp); 146 } 147 } else { 148 free(aclp); 149 aclp = NULL; 150 break; 151 } 152 } 153 154 *aclcnt = cnt; 155 return (aclp); 156} 157 158/* 159 * Check if acl is trivial 160 * This is a FreeBSD acl_is_trivial_np() implementation for Solaris 161 */ 162static int 163sun_acl_is_trivial(void *aclp, int aclcnt, mode_t mode, int is_nfs4, 164 int is_dir, int *trivialp) 165{ 166#if ARCHIVE_ACL_SUNOS_NFS4 167 int i, p; 168 const uint32_t rperm = ACE_READ_DATA; 169 const uint32_t wperm = ACE_WRITE_DATA | ACE_APPEND_DATA; 170 const uint32_t eperm = ACE_EXECUTE; 171 const uint32_t pubset = ACE_READ_ATTRIBUTES | ACE_READ_NAMED_ATTRS | 172 ACE_READ_ACL | ACE_SYNCHRONIZE; 173 const uint32_t ownset = pubset | ACE_WRITE_ATTRIBUTES | 174 ACE_WRITE_NAMED_ATTRS | ACE_WRITE_ACL | ACE_WRITE_OWNER; 175 176 ace_t *ace; 177 ace_t tace[6]; 178#endif 179 180 if (aclp == NULL || trivialp == NULL) 181 return (-1); 182 183 *trivialp = 0; 184 185 /* 186 * POSIX.1e ACLs marked with ACL_IS_TRIVIAL are compatible with 187 * FreeBSD acl_is_trivial_np(). On Solaris they have 4 entries, 188 * including mask. 189 */ 190 if (!is_nfs4) { 191 if (aclcnt == 4) 192 *trivialp = 1; 193 return (0); 194 } 195 196#if ARCHIVE_ACL_SUNOS_NFS4 197 /* 198 * Continue with checking NFSv4 ACLs 199 * 200 * Create list of trivial ace's to be compared 201 */ 202 203 /* owner@ allow pre */ 204 tace[0].a_flags = ACE_OWNER; 205 tace[0].a_type = ACE_ACCESS_ALLOWED_ACE_TYPE; 206 tace[0].a_access_mask = 0; 207 208 /* owner@ deny */ 209 tace[1].a_flags = ACE_OWNER; 210 tace[1].a_type = ACE_ACCESS_DENIED_ACE_TYPE; 211 tace[1].a_access_mask = 0; 212 213 /* group@ deny */ 214 tace[2].a_flags = ACE_GROUP | ACE_IDENTIFIER_GROUP; 215 tace[2].a_type = ACE_ACCESS_DENIED_ACE_TYPE; 216 tace[2].a_access_mask = 0; 217 218 /* owner@ allow */ 219 tace[3].a_flags = ACE_OWNER; 220 tace[3].a_type = ACE_ACCESS_ALLOWED_ACE_TYPE; 221 tace[3].a_access_mask = ownset; 222 223 /* group@ allow */ 224 tace[4].a_flags = ACE_GROUP | ACE_IDENTIFIER_GROUP; 225 tace[4].a_type = ACE_ACCESS_ALLOWED_ACE_TYPE; 226 tace[4].a_access_mask = pubset; 227 228 /* everyone@ allow */ 229 tace[5].a_flags = ACE_EVERYONE; 230 tace[5].a_type = ACE_ACCESS_ALLOWED_ACE_TYPE; 231 tace[5].a_access_mask = pubset; 232 233 /* Permissions for everyone@ */ 234 if (mode & 0004) 235 tace[5].a_access_mask |= rperm; 236 if (mode & 0002) 237 tace[5].a_access_mask |= wperm; 238 if (mode & 0001) 239 tace[5].a_access_mask |= eperm; 240 241 /* Permissions for group@ */ 242 if (mode & 0040) 243 tace[4].a_access_mask |= rperm; 244 else if (mode & 0004) 245 tace[2].a_access_mask |= rperm; 246 if (mode & 0020) 247 tace[4].a_access_mask |= wperm; 248 else if (mode & 0002) 249 tace[2].a_access_mask |= wperm; 250 if (mode & 0010) 251 tace[4].a_access_mask |= eperm; 252 else if (mode & 0001) 253 tace[2].a_access_mask |= eperm; 254 255 /* Permissions for owner@ */ 256 if (mode & 0400) { 257 tace[3].a_access_mask |= rperm; 258 if (!(mode & 0040) && (mode & 0004)) 259 tace[0].a_access_mask |= rperm; 260 } else if ((mode & 0040) || (mode & 0004)) 261 tace[1].a_access_mask |= rperm; 262 if (mode & 0200) { 263 tace[3].a_access_mask |= wperm; 264 if (!(mode & 0020) && (mode & 0002)) 265 tace[0].a_access_mask |= wperm; 266 } else if ((mode & 0020) || (mode & 0002)) 267 tace[1].a_access_mask |= wperm; 268 if (mode & 0100) { 269 tace[3].a_access_mask |= eperm; 270 if (!(mode & 0010) && (mode & 0001)) 271 tace[0].a_access_mask |= eperm; 272 } else if ((mode & 0010) || (mode & 0001)) 273 tace[1].a_access_mask |= eperm; 274 275 /* Check if the acl count matches */ 276 p = 3; 277 for (i = 0; i < 3; i++) { 278 if (tace[i].a_access_mask != 0) 279 p++; 280 } 281 if (aclcnt != p) 282 return (0); 283 284 p = 0; 285 for (i = 0; i < 6; i++) { 286 if (tace[i].a_access_mask != 0) { 287 ace = &((ace_t *)aclp)[p]; 288 /* 289 * Illumos added ACE_DELETE_CHILD to write perms for 290 * directories. We have to check against that, too. 291 */ 292 if (ace->a_flags != tace[i].a_flags || 293 ace->a_type != tace[i].a_type || 294 (ace->a_access_mask != tace[i].a_access_mask && 295 (!is_dir || (tace[i].a_access_mask & wperm) == 0 || 296 ace->a_access_mask != 297 (tace[i].a_access_mask | ACE_DELETE_CHILD)))) 298 return (0); 299 p++; 300 } 301 } 302 303 *trivialp = 1; 304#else /* !ARCHIVE_ACL_SUNOS_NFS4 */ 305 (void)is_dir; /* UNUSED */ 306 (void)aclp; /* UNUSED */ 307#endif /* !ARCHIVE_ACL_SUNOS_NFS4 */ 308 return (0); 309} 310 311/* 312 * Translate Solaris POSIX.1e and NFSv4 ACLs into libarchive internal ACL 313 */ 314static int 315translate_acl(struct archive_read_disk *a, 316 struct archive_entry *entry, void *aclp, int aclcnt, 317 int default_entry_acl_type) 318{ 319 int e, i; 320 int ae_id, ae_tag, ae_perm; 321 int entry_acl_type; 322 const char *ae_name; 323 aclent_t *aclent; 324#if ARCHIVE_ACL_SUNOS_NFS4 325 ace_t *ace; 326#endif 327 328 if (aclcnt <= 0) 329 return (ARCHIVE_OK); 330 331 for (e = 0; e < aclcnt; e++) { 332 ae_name = NULL; 333 ae_tag = 0; 334 ae_perm = 0; 335 336#if ARCHIVE_ACL_SUNOS_NFS4 337 if (default_entry_acl_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) { 338 ace = &((ace_t *)aclp)[e]; 339 ae_id = ace->a_who; 340 341 switch(ace->a_type) { 342 case ACE_ACCESS_ALLOWED_ACE_TYPE: 343 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW; 344 break; 345 case ACE_ACCESS_DENIED_ACE_TYPE: 346 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DENY; 347 break; 348 case ACE_SYSTEM_AUDIT_ACE_TYPE: 349 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS; 350 break; 351 case ACE_SYSTEM_ALARM_ACE_TYPE: 352 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALARM; 353 break; 354 default: 355 /* Unknown entry type, skip */ 356 continue; 357 } 358 359 if ((ace->a_flags & ACE_OWNER) != 0) 360 ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ; 361 else if ((ace->a_flags & ACE_GROUP) != 0) 362 ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; 363 else if ((ace->a_flags & ACE_EVERYONE) != 0) 364 ae_tag = ARCHIVE_ENTRY_ACL_EVERYONE; 365 else if ((ace->a_flags & ACE_IDENTIFIER_GROUP) != 0) { 366 ae_tag = ARCHIVE_ENTRY_ACL_GROUP; 367 ae_name = archive_read_disk_gname(&a->archive, 368 ae_id); 369 } else { 370 ae_tag = ARCHIVE_ENTRY_ACL_USER; 371 ae_name = archive_read_disk_uname(&a->archive, 372 ae_id); 373 } 374 375 for (i = 0; i < acl_nfs4_flag_map_size; ++i) { 376 if ((ace->a_flags & 377 acl_nfs4_flag_map[i].p_perm) != 0) 378 ae_perm |= acl_nfs4_flag_map[i].a_perm; 379 } 380 381 for (i = 0; i < acl_nfs4_perm_map_size; ++i) { 382 if ((ace->a_access_mask & 383 acl_nfs4_perm_map[i].p_perm) != 0) 384 ae_perm |= acl_nfs4_perm_map[i].a_perm; 385 } 386 } else 387#endif /* ARCHIVE_ACL_SUNOS_NFS4 */ 388 if (default_entry_acl_type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS) { 389 aclent = &((aclent_t *)aclp)[e]; 390 if ((aclent->a_type & ACL_DEFAULT) != 0) 391 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT; 392 else 393 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS; 394 ae_id = aclent->a_id; 395 396 switch(aclent->a_type) { 397 case DEF_USER: 398 case USER: 399 ae_name = archive_read_disk_uname(&a->archive, 400 ae_id); 401 ae_tag = ARCHIVE_ENTRY_ACL_USER; 402 break; 403 case DEF_GROUP: 404 case GROUP: 405 ae_name = archive_read_disk_gname(&a->archive, 406 ae_id); 407 ae_tag = ARCHIVE_ENTRY_ACL_GROUP; 408 break; 409 case DEF_CLASS_OBJ: 410 case CLASS_OBJ: 411 ae_tag = ARCHIVE_ENTRY_ACL_MASK; 412 break; 413 case DEF_USER_OBJ: 414 case USER_OBJ: 415 ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ; 416 break; 417 case DEF_GROUP_OBJ: 418 case GROUP_OBJ: 419 ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; 420 break; 421 case DEF_OTHER_OBJ: 422 case OTHER_OBJ: 423 ae_tag = ARCHIVE_ENTRY_ACL_OTHER; 424 break; 425 default: 426 /* Unknown tag type, skip */ 427 continue; 428 } 429 430 for (i = 0; i < acl_posix_perm_map_size; ++i) { 431 if ((aclent->a_perm & 432 acl_posix_perm_map[i].p_perm) != 0) 433 ae_perm |= acl_posix_perm_map[i].a_perm; 434 } 435 } else 436 return (ARCHIVE_WARN); 437 438 archive_entry_acl_add_entry(entry, entry_acl_type, 439 ae_perm, ae_tag, ae_id, ae_name); 440 } 441 return (ARCHIVE_OK); 442} 443 444static int 445set_acl(struct archive *a, int fd, const char *name, 446 struct archive_acl *abstract_acl, __LA_MODE_T mode, 447 int ae_requested_type, const char *tname) 448{ 449 aclent_t *aclent; 450#if ARCHIVE_ACL_SUNOS_NFS4 451 ace_t *ace; 452#endif 453 int cmd, e, r; 454 void *aclp; 455 int ret; 456 int ae_type, ae_permset, ae_tag, ae_id; 457 int perm_map_size; 458 const acl_perm_map_t *perm_map; 459 uid_t ae_uid; 460 gid_t ae_gid; 461 const char *ae_name; 462 int entries; 463 int i; 464 465 ret = ARCHIVE_OK; 466 entries = archive_acl_reset(abstract_acl, ae_requested_type); 467 if (entries == 0) 468 return (ARCHIVE_OK); 469 470 switch (ae_requested_type) { 471 case ARCHIVE_ENTRY_ACL_TYPE_POSIX1E: 472 cmd = SETACL; 473 aclp = malloc(entries * sizeof(aclent_t)); 474 break; 475#if ARCHIVE_ACL_SUNOS_NFS4 476 case ARCHIVE_ENTRY_ACL_TYPE_NFS4: 477 cmd = ACE_SETACL; 478 aclp = malloc(entries * sizeof(ace_t)); 479 480 break; 481#endif 482 default: 483 errno = ENOENT; 484 archive_set_error(a, errno, "Unsupported ACL type"); 485 return (ARCHIVE_FAILED); 486 } 487 488 if (aclp == NULL) { 489 archive_set_error(a, errno, 490 "Can't allocate memory for acl buffer"); 491 return (ARCHIVE_FAILED); 492 } 493 494 if (S_ISLNK(mode)) { 495 /* Skip ACLs on symbolic links */ 496 ret = ARCHIVE_OK; 497 goto exit_free; 498 } 499 500 e = 0; 501 502 while (archive_acl_next(a, abstract_acl, ae_requested_type, &ae_type, 503 &ae_permset, &ae_tag, &ae_id, &ae_name) == ARCHIVE_OK) { 504 aclent = NULL; 505#if ARCHIVE_ACL_SUNOS_NFS4 506 ace = NULL; 507#endif 508 if (cmd == SETACL) { 509 aclent = &((aclent_t *)aclp)[e]; 510 aclent->a_id = -1; 511 aclent->a_type = 0; 512 aclent->a_perm = 0; 513 } 514#if ARCHIVE_ACL_SUNOS_NFS4 515 else { /* cmd == ACE_SETACL */ 516 ace = &((ace_t *)aclp)[e]; 517 ace->a_who = -1; 518 ace->a_access_mask = 0; 519 ace->a_flags = 0; 520 } 521#endif /* ARCHIVE_ACL_SUNOS_NFS4 */ 522 523 switch (ae_tag) { 524 case ARCHIVE_ENTRY_ACL_USER: 525 ae_uid = archive_write_disk_uid(a, ae_name, ae_id); 526 if (aclent != NULL) { 527 aclent->a_id = ae_uid; 528 aclent->a_type |= USER; 529 } 530#if ARCHIVE_ACL_SUNOS_NFS4 531 else { 532 ace->a_who = ae_uid; 533 } 534#endif 535 break; 536 case ARCHIVE_ENTRY_ACL_GROUP: 537 ae_gid = archive_write_disk_gid(a, ae_name, ae_id); 538 if (aclent != NULL) { 539 aclent->a_id = ae_gid; 540 aclent->a_type |= GROUP; 541 } 542#if ARCHIVE_ACL_SUNOS_NFS4 543 else { 544 ace->a_who = ae_gid; 545 ace->a_flags |= ACE_IDENTIFIER_GROUP; 546 } 547#endif 548 break; 549 case ARCHIVE_ENTRY_ACL_USER_OBJ: 550 if (aclent != NULL) 551 aclent->a_type |= USER_OBJ; 552#if ARCHIVE_ACL_SUNOS_NFS4 553 else { 554 ace->a_flags |= ACE_OWNER; 555 } 556#endif 557 break; 558 case ARCHIVE_ENTRY_ACL_GROUP_OBJ: 559 if (aclent != NULL) 560 aclent->a_type |= GROUP_OBJ; 561#if ARCHIVE_ACL_SUNOS_NFS4 562 else { 563 ace->a_flags |= ACE_GROUP; 564 ace->a_flags |= ACE_IDENTIFIER_GROUP; 565 } 566#endif 567 break; 568 case ARCHIVE_ENTRY_ACL_MASK: 569 if (aclent != NULL) 570 aclent->a_type |= CLASS_OBJ; 571 break; 572 case ARCHIVE_ENTRY_ACL_OTHER: 573 if (aclent != NULL) 574 aclent->a_type |= OTHER_OBJ; 575 break; 576#if ARCHIVE_ACL_SUNOS_NFS4 577 case ARCHIVE_ENTRY_ACL_EVERYONE: 578 if (ace != NULL) 579 ace->a_flags |= ACE_EVERYONE; 580 break; 581#endif 582 default: 583 archive_set_error(a, ARCHIVE_ERRNO_MISC, 584 "Unsupported ACL tag"); 585 ret = ARCHIVE_FAILED; 586 goto exit_free; 587 } 588 589 r = 0; 590 switch (ae_type) { 591#if ARCHIVE_ACL_SUNOS_NFS4 592 case ARCHIVE_ENTRY_ACL_TYPE_ALLOW: 593 if (ace != NULL) 594 ace->a_type = ACE_ACCESS_ALLOWED_ACE_TYPE; 595 else 596 r = -1; 597 break; 598 case ARCHIVE_ENTRY_ACL_TYPE_DENY: 599 if (ace != NULL) 600 ace->a_type = ACE_ACCESS_DENIED_ACE_TYPE; 601 else 602 r = -1; 603 break; 604 case ARCHIVE_ENTRY_ACL_TYPE_AUDIT: 605 if (ace != NULL) 606 ace->a_type = ACE_SYSTEM_AUDIT_ACE_TYPE; 607 else 608 r = -1; 609 break; 610 case ARCHIVE_ENTRY_ACL_TYPE_ALARM: 611 if (ace != NULL) 612 ace->a_type = ACE_SYSTEM_ALARM_ACE_TYPE; 613 else 614 r = -1; 615 break; 616#endif 617 case ARCHIVE_ENTRY_ACL_TYPE_ACCESS: 618 if (aclent == NULL) 619 r = -1; 620 break; 621 case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT: 622 if (aclent != NULL) 623 aclent->a_type |= ACL_DEFAULT; 624 else 625 r = -1; 626 break; 627 default: 628 archive_set_error(a, ARCHIVE_ERRNO_MISC, 629 "Unsupported ACL entry type"); 630 ret = ARCHIVE_FAILED; 631 goto exit_free; 632 } 633 634 if (r != 0) { 635 errno = EINVAL; 636 archive_set_error(a, errno, 637 "Failed to set ACL entry type"); 638 ret = ARCHIVE_FAILED; 639 goto exit_free; 640 } 641 642#if ARCHIVE_ACL_SUNOS_NFS4 643 if (ae_requested_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) { 644 perm_map_size = acl_nfs4_perm_map_size; 645 perm_map = acl_nfs4_perm_map; 646 } else { 647#endif 648 perm_map_size = acl_posix_perm_map_size; 649 perm_map = acl_posix_perm_map; 650#if ARCHIVE_ACL_SUNOS_NFS4 651 } 652#endif 653 for (i = 0; i < perm_map_size; ++i) { 654 if (ae_permset & perm_map[i].a_perm) { 655#if ARCHIVE_ACL_SUNOS_NFS4 656 if (ae_requested_type == 657 ARCHIVE_ENTRY_ACL_TYPE_NFS4) 658 ace->a_access_mask |= 659 perm_map[i].p_perm; 660 else 661#endif 662 aclent->a_perm |= perm_map[i].p_perm; 663 } 664 } 665 666#if ARCHIVE_ACL_SUNOS_NFS4 667 if (ae_requested_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) { 668 for (i = 0; i < acl_nfs4_flag_map_size; ++i) { 669 if (ae_permset & acl_nfs4_flag_map[i].a_perm) { 670 ace->a_flags |= 671 acl_nfs4_flag_map[i].p_perm; 672 } 673 } 674 } 675#endif 676 e++; 677 } 678 679 /* Try restoring the ACL through 'fd' if we can. */ 680 if (fd >= 0) { 681 if (facl(fd, cmd, entries, aclp) == 0) 682 ret = ARCHIVE_OK; 683 else { 684 if (errno == EOPNOTSUPP) { 685 /* Filesystem doesn't support ACLs */ 686 ret = ARCHIVE_OK; 687 } else { 688 archive_set_error(a, errno, 689 "Failed to set acl on fd: %s", tname); 690 ret = ARCHIVE_WARN; 691 } 692 } 693 } else if (acl(name, cmd, entries, aclp) != 0) { 694 if (errno == EOPNOTSUPP) { 695 /* Filesystem doesn't support ACLs */ 696 ret = ARCHIVE_OK; 697 } else { 698 archive_set_error(a, errno, "Failed to set acl: %s", 699 tname); 700 ret = ARCHIVE_WARN; 701 } 702 } 703exit_free: 704 free(aclp); 705 return (ret); 706} 707 708int 709archive_read_disk_entry_setup_acls(struct archive_read_disk *a, 710 struct archive_entry *entry, int *fd) 711{ 712 const char *accpath; 713 void *aclp; 714 int aclcnt; 715 int r; 716 717 accpath = NULL; 718 719 if (*fd < 0) { 720 accpath = archive_read_disk_entry_setup_path(a, entry, fd); 721 if (accpath == NULL) 722 return (ARCHIVE_WARN); 723 } 724 725 archive_entry_acl_clear(entry); 726 727 aclp = NULL; 728 729#if ARCHIVE_ACL_SUNOS_NFS4 730 if (*fd >= 0) 731 aclp = sunacl_get(ACE_GETACL, &aclcnt, *fd, NULL); 732 else if ((!a->follow_symlinks) 733 && (archive_entry_filetype(entry) == AE_IFLNK)) 734 /* We can't get the ACL of a symlink, so we assume it can't 735 have one. */ 736 aclp = NULL; 737 else 738 aclp = sunacl_get(ACE_GETACL, &aclcnt, 0, accpath); 739 740 if (aclp != NULL && sun_acl_is_trivial(aclp, aclcnt, 741 archive_entry_mode(entry), 1, S_ISDIR(archive_entry_mode(entry)), 742 &r) == 0 && r == 1) { 743 free(aclp); 744 aclp = NULL; 745 return (ARCHIVE_OK); 746 } 747 748 if (aclp != NULL) { 749 r = translate_acl(a, entry, aclp, aclcnt, 750 ARCHIVE_ENTRY_ACL_TYPE_NFS4); 751 free(aclp); 752 aclp = NULL; 753 754 if (r != ARCHIVE_OK) { 755 archive_set_error(&a->archive, errno, 756 "Couldn't translate NFSv4 ACLs"); 757 } 758 return (r); 759 } 760#endif /* ARCHIVE_ACL_SUNOS_NFS4 */ 761 762 /* Retrieve POSIX.1e ACLs from file. */ 763 if (*fd >= 0) 764 aclp = sunacl_get(GETACL, &aclcnt, *fd, NULL); 765 else if ((!a->follow_symlinks) 766 && (archive_entry_filetype(entry) == AE_IFLNK)) 767 /* We can't get the ACL of a symlink, so we assume it can't 768 have one. */ 769 aclp = NULL; 770 else 771 aclp = sunacl_get(GETACL, &aclcnt, 0, accpath); 772 773 /* Ignore "trivial" ACLs that just mirror the file mode. */ 774 if (aclp != NULL && sun_acl_is_trivial(aclp, aclcnt, 775 archive_entry_mode(entry), 0, S_ISDIR(archive_entry_mode(entry)), 776 &r) == 0 && r == 1) { 777 free(aclp); 778 aclp = NULL; 779 } 780 781 if (aclp != NULL) 782 { 783 r = translate_acl(a, entry, aclp, aclcnt, 784 ARCHIVE_ENTRY_ACL_TYPE_ACCESS); 785 free(aclp); 786 aclp = NULL; 787 788 if (r != ARCHIVE_OK) { 789 archive_set_error(&a->archive, errno, 790 "Couldn't translate access ACLs"); 791 return (r); 792 } 793 } 794 795 return (ARCHIVE_OK); 796} 797 798int 799archive_write_disk_set_acls(struct archive *a, int fd, const char *name, 800 struct archive_acl *abstract_acl, __LA_MODE_T mode) 801{ 802 int ret = ARCHIVE_OK; 803 804 (void)mode; /* UNUSED */ 805 806 if ((archive_acl_types(abstract_acl) 807 & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) { 808 /* Solaris writes POSIX.1e access and default ACLs together */ 809 ret = set_acl(a, fd, name, abstract_acl, mode, 810 ARCHIVE_ENTRY_ACL_TYPE_POSIX1E, "posix1e"); 811 812 /* Simultaneous POSIX.1e and NFSv4 is not supported */ 813 return (ret); 814 } 815#if ARCHIVE_ACL_SUNOS_NFS4 816 else if ((archive_acl_types(abstract_acl) & 817 ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) { 818 ret = set_acl(a, fd, name, abstract_acl, mode, 819 ARCHIVE_ENTRY_ACL_TYPE_NFS4, "nfs4"); 820 } 821#endif 822 return (ret); 823} 824#endif /* ARCHIVE_ACL_SUNOS */ 825