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 #include "test.h" 26 27 #if ARCHIVE_ACL_FREEBSD || ARCHIVE_ACL_DARWIN || ARCHIVE_ACL_LIBACL 28 static const acl_perm_t acl_perms[] = { 29 #if ARCHIVE_ACL_DARWIN 30 ACL_READ_DATA, 31 ACL_LIST_DIRECTORY, 32 ACL_WRITE_DATA, 33 ACL_ADD_FILE, 34 ACL_EXECUTE, 35 ACL_SEARCH, 36 ACL_DELETE, 37 ACL_APPEND_DATA, 38 ACL_ADD_SUBDIRECTORY, 39 ACL_DELETE_CHILD, 40 ACL_READ_ATTRIBUTES, 41 ACL_WRITE_ATTRIBUTES, 42 ACL_READ_EXTATTRIBUTES, 43 ACL_WRITE_EXTATTRIBUTES, 44 ACL_READ_SECURITY, 45 ACL_WRITE_SECURITY, 46 ACL_CHANGE_OWNER, 47 ACL_SYNCHRONIZE 48 #else /* !ARCHIVE_ACL_DARWIN */ 49 ACL_EXECUTE, 50 ACL_WRITE, 51 ACL_READ, 52 #if ARCHIVE_ACL_FREEBSD_NFS4 53 ACL_READ_DATA, 54 ACL_LIST_DIRECTORY, 55 ACL_WRITE_DATA, 56 ACL_ADD_FILE, 57 ACL_APPEND_DATA, 58 ACL_ADD_SUBDIRECTORY, 59 ACL_READ_NAMED_ATTRS, 60 ACL_WRITE_NAMED_ATTRS, 61 ACL_DELETE_CHILD, 62 ACL_READ_ATTRIBUTES, 63 ACL_WRITE_ATTRIBUTES, 64 ACL_DELETE, 65 ACL_READ_ACL, 66 ACL_WRITE_ACL, 67 ACL_WRITE_OWNER, 68 ACL_SYNCHRONIZE 69 #endif /* ARCHIVE_ACL_FREEBSD_NFS4 */ 70 #endif /* !ARCHIVE_ACL_DARWIN */ 71 }; 72 #if ARCHIVE_ACL_DARWIN || ARCHIVE_ACL_FREEBSD_NFS4 73 static const acl_flag_t acl_flags[] = { 74 #if ARCHIVE_ACL_DARWIN 75 ACL_ENTRY_INHERITED, 76 ACL_ENTRY_FILE_INHERIT, 77 ACL_ENTRY_DIRECTORY_INHERIT, 78 ACL_ENTRY_LIMIT_INHERIT, 79 ACL_ENTRY_ONLY_INHERIT 80 #else /* ARCHIVE_ACL_FREEBSD_NFS4 */ 81 ACL_ENTRY_FILE_INHERIT, 82 ACL_ENTRY_DIRECTORY_INHERIT, 83 ACL_ENTRY_NO_PROPAGATE_INHERIT, 84 ACL_ENTRY_INHERIT_ONLY, 85 ACL_ENTRY_SUCCESSFUL_ACCESS, 86 ACL_ENTRY_FAILED_ACCESS, 87 #ifdef ACL_ENTRY_INHERITED 88 ACL_ENTRY_INHERITED 89 #endif 90 #endif /* ARCHIVE_ACL_FREEBSD_NFS4 */ 91 }; 92 #endif /* ARCHIVE_ACL_DARWIN || ARCHIVE_ACL_FREEBSD_NFS4 */ 93 94 /* 95 * Compare two ACL entries on FreeBSD or on Mac OS X 96 */ 97 static int 98 compare_acl_entry(acl_entry_t ae_a, acl_entry_t ae_b, int is_nfs4) 99 { 100 acl_tag_t tag_a, tag_b; 101 acl_permset_t permset_a, permset_b; 102 int perm_a, perm_b, perm_start, perm_end; 103 void *qual_a, *qual_b; 104 #if ARCHIVE_ACL_FREEBSD_NFS4 105 acl_entry_type_t type_a, type_b; 106 #endif 107 #if ARCHIVE_ACL_FREEBSD_NFS4 || ARCHIVE_ACL_DARWIN 108 acl_flagset_t flagset_a, flagset_b; 109 int flag_a, flag_b; 110 #endif 111 int i, r; 112 113 114 /* Compare ACL tag */ 115 r = acl_get_tag_type(ae_a, &tag_a); 116 failure("acl_get_tag_type() error: %s", strerror(errno)); 117 if (assertEqualInt(r, 0) == 0) 118 return (-1); 119 r = acl_get_tag_type(ae_b, &tag_b); 120 failure("acl_get_tag_type() error: %s", strerror(errno)); 121 if (assertEqualInt(r, 0) == 0) 122 return (-1); 123 if (tag_a != tag_b) 124 return (0); 125 126 /* Compare ACL qualifier */ 127 #if ARCHIVE_ACL_DARWIN 128 if (tag_a == ACL_EXTENDED_ALLOW || tag_b == ACL_EXTENDED_DENY) 129 #else 130 if (tag_a == ACL_USER || tag_a == ACL_GROUP) 131 #endif 132 { 133 qual_a = acl_get_qualifier(ae_a); 134 failure("acl_get_qualifier() error: %s", strerror(errno)); 135 if (assert(qual_a != NULL) == 0) 136 return (-1); 137 qual_b = acl_get_qualifier(ae_b); 138 failure("acl_get_qualifier() error: %s", strerror(errno)); 139 if (assert(qual_b != NULL) == 0) { 140 acl_free(qual_a); 141 return (-1); 142 } 143 #if ARCHIVE_ACL_DARWIN 144 if (memcmp(((guid_t *)qual_a)->g_guid, 145 ((guid_t *)qual_b)->g_guid, KAUTH_GUID_SIZE) != 0) 146 #else 147 if ((tag_a == ACL_USER && 148 (*(uid_t *)qual_a != *(uid_t *)qual_b)) || 149 (tag_a == ACL_GROUP && 150 (*(gid_t *)qual_a != *(gid_t *)qual_b))) 151 #endif 152 { 153 acl_free(qual_a); 154 acl_free(qual_b); 155 return (0); 156 } 157 acl_free(qual_a); 158 acl_free(qual_b); 159 } 160 161 #if ARCHIVE_ACL_FREEBSD_NFS4 162 if (is_nfs4) { 163 /* Compare NFS4 ACL type */ 164 r = acl_get_entry_type_np(ae_a, &type_a); 165 failure("acl_get_entry_type_np() error: %s", strerror(errno)); 166 if (assertEqualInt(r, 0) == 0) 167 return (-1); 168 r = acl_get_entry_type_np(ae_b, &type_b); 169 failure("acl_get_entry_type_np() error: %s", strerror(errno)); 170 if (assertEqualInt(r, 0) == 0) 171 return (-1); 172 if (type_a != type_b) 173 return (0); 174 } 175 #endif 176 177 /* Compare ACL perms */ 178 r = acl_get_permset(ae_a, &permset_a); 179 failure("acl_get_permset() error: %s", strerror(errno)); 180 if (assertEqualInt(r, 0) == 0) 181 return (-1); 182 r = acl_get_permset(ae_b, &permset_b); 183 failure("acl_get_permset() error: %s", strerror(errno)); 184 if (assertEqualInt(r, 0) == 0) 185 return (-1); 186 187 perm_start = 0; 188 perm_end = (int)(sizeof(acl_perms) / sizeof(acl_perms[0])); 189 #if ARCHIVE_ACL_FREEBSD_NFS4 190 if (is_nfs4) 191 perm_start = 3; 192 else 193 perm_end = 3; 194 #endif 195 /* Cycle through all perms and compare their value */ 196 for (i = perm_start; i < perm_end; i++) { 197 #if ARCHIVE_ACL_LIBACL 198 perm_a = acl_get_perm(permset_a, acl_perms[i]); 199 perm_b = acl_get_perm(permset_b, acl_perms[i]); 200 #else 201 perm_a = acl_get_perm_np(permset_a, acl_perms[i]); 202 perm_b = acl_get_perm_np(permset_b, acl_perms[i]); 203 #endif 204 if (perm_a == -1 || perm_b == -1) 205 return (-1); 206 if (perm_a != perm_b) 207 return (0); 208 } 209 210 #if ARCHIVE_ACL_FREEBSD_NFS4 || ARCHIVE_ACL_DARWIN 211 if (is_nfs4) { 212 r = acl_get_flagset_np(ae_a, &flagset_a); 213 failure("acl_get_flagset_np() error: %s", strerror(errno)); 214 if (assertEqualInt(r, 0) == 0) 215 return (-1); 216 r = acl_get_flagset_np(ae_b, &flagset_b); 217 failure("acl_get_flagset_np() error: %s", strerror(errno)); 218 if (assertEqualInt(r, 0) == 0) 219 return (-1); 220 /* Cycle through all flags and compare their status */ 221 for (i = 0; i < (int)(sizeof(acl_flags) / sizeof(acl_flags[0])); 222 i++) { 223 flag_a = acl_get_flag_np(flagset_a, acl_flags[i]); 224 flag_b = acl_get_flag_np(flagset_b, acl_flags[i]); 225 if (flag_a == -1 || flag_b == -1) 226 return (-1); 227 if (flag_a != flag_b) 228 return (0); 229 } 230 } 231 #else /* ARCHIVE_ACL_FREEBSD_NFS4 || ARCHIVE_ACL_DARWIN */ 232 (void)is_nfs4; /* UNUSED */ 233 #endif 234 return (1); 235 } 236 #endif /* ARCHIVE_ACL_FREEBSD || ARCHIVE_ACL_DARWIN || ARCHIVE_ACL_LIBACL */ 237 238 #if ARCHIVE_ACL_SUPPORT 239 /* 240 * Clear default ACLs or inheritance flags 241 */ 242 static void 243 clear_inheritance_flags(const char *path, int type) 244 { 245 switch (type) { 246 case ARCHIVE_TEST_ACL_TYPE_POSIX1E: 247 #if ARCHIVE_ACL_POSIX1E 248 #if !ARCHIVE_ACL_SUNOS 249 acl_delete_def_file(path); 250 #else 251 /* Solaris */ 252 setTestAcl(path); 253 #endif 254 #endif /* ARCHIVE_ACL_POSIX1E */ 255 break; 256 case ARCHIVE_TEST_ACL_TYPE_NFS4: 257 #if ARCHIVE_ACL_NFS4 258 setTestAcl(path); 259 #endif 260 break; 261 default: 262 (void)path; /* UNUSED */ 263 break; 264 } 265 } 266 267 static int 268 compare_acls(const char *path_a, const char *path_b) 269 { 270 int ret = 1; 271 int is_nfs4 = 0; 272 #if ARCHIVE_ACL_SUNOS 273 void *acl_a, *acl_b; 274 int aclcnt_a, aclcnt_b; 275 aclent_t *aclent_a, *aclent_b; 276 ace_t *ace_a, *ace_b; 277 int e; 278 #elif ARCHIVE_ACL_DARWIN || ARCHIVE_ACL_FREEBSD || ARCHIVE_ACL_LIBACL 279 acl_t acl_a, acl_b; 280 acl_entry_t aclent_a, aclent_b; 281 int a, b, r; 282 #endif 283 #if ARCHIVE_ACL_LIBRICHACL 284 struct richacl *richacl_a, *richacl_b; 285 286 richacl_a = NULL; 287 richacl_b = NULL; 288 #endif 289 290 #if ARCHIVE_ACL_DARWIN || ARCHIVE_ACL_FREEBSD || ARCHIVE_ACL_LIBACL || \ 291 ARCHIVE_ACL_SUNOS 292 acl_a = NULL; 293 acl_b = NULL; 294 #endif 295 #if ARCHIVE_ACL_SUNOS 296 acl_a = sunacl_get(GETACL, &aclcnt_a, 0, path_a); 297 if (acl_a == NULL) { 298 #if ARCHIVE_ACL_SUNOS_NFS4 299 is_nfs4 = 1; 300 acl_a = sunacl_get(ACE_GETACL, &aclcnt_a, 0, path_a); 301 #endif 302 failure("acl_get() error: %s", strerror(errno)); 303 if (assert(acl_a != NULL) == 0) 304 return (-1); 305 #if ARCHIVE_ACL_SUNOS_NFS4 306 acl_b = sunacl_get(ACE_GETACL, &aclcnt_b, 0, path_b); 307 #endif 308 } else 309 acl_b = sunacl_get(GETACL, &aclcnt_b, 0, path_b); 310 if (acl_b == NULL && (errno == ENOSYS || errno == ENOTSUP)) { 311 free(acl_a); 312 return (0); 313 } 314 failure("acl_get() error: %s", strerror(errno)); 315 if (assert(acl_b != NULL) == 0) { 316 free(acl_a); 317 return (-1); 318 } 319 320 if (aclcnt_a != aclcnt_b) { 321 ret = 0; 322 goto exit_free; 323 } 324 325 for (e = 0; e < aclcnt_a; e++) { 326 if (!is_nfs4) { 327 aclent_a = &((aclent_t *)acl_a)[e]; 328 aclent_b = &((aclent_t *)acl_b)[e]; 329 if (aclent_a->a_type != aclent_b->a_type || 330 aclent_a->a_id != aclent_b->a_id || 331 aclent_a->a_perm != aclent_b->a_perm) { 332 ret = 0; 333 goto exit_free; 334 } 335 } 336 #if ARCHIVE_ACL_SUNOS_NFS4 337 else { 338 ace_a = &((ace_t *)acl_a)[e]; 339 ace_b = &((ace_t *)acl_b)[e]; 340 if (ace_a->a_who != ace_b->a_who || 341 ace_a->a_access_mask != ace_b->a_access_mask || 342 ace_a->a_flags != ace_b->a_flags || 343 ace_a->a_type != ace_b->a_type) { 344 ret = 0; 345 goto exit_free; 346 } 347 } 348 #endif 349 } 350 #else /* !ARCHIVE_ACL_SUNOS */ 351 #if ARCHIVE_ACL_LIBRICHACL 352 richacl_a = richacl_get_file(path_a); 353 #if !ARCHIVE_ACL_LIBACL 354 if (richacl_a == NULL && 355 (errno == ENODATA || errno == ENOTSUP || errno == ENOSYS)) 356 return (0); 357 failure("richacl_get_file() error: %s (%s)", path_a, strerror(errno)); 358 if (assert(richacl_a != NULL) == 0) 359 return (-1); 360 #endif 361 if (richacl_a != NULL) { 362 richacl_b = richacl_get_file(path_b); 363 if (richacl_b == NULL && 364 (errno == ENODATA || errno == ENOTSUP || errno == ENOSYS)) { 365 richacl_free(richacl_a); 366 return (0); 367 } 368 failure("richacl_get_file() error: %s (%s)", path_b, 369 strerror(errno)); 370 if (assert(richacl_b != NULL) == 0) { 371 richacl_free(richacl_a); 372 return (-1); 373 } 374 if (richacl_compare(richacl_a, richacl_b) == 0) 375 ret = 0; 376 richacl_free(richacl_a); 377 richacl_free(richacl_b); 378 return (ret); 379 } 380 #endif /* ARCHIVE_ACL_LIBRICHACL */ 381 #if ARCHIVE_ACL_DARWIN || ARCHIVE_ACL_FREEBSD || ARCHIVE_ACL_LIBACL 382 #if ARCHIVE_ACL_DARWIN 383 is_nfs4 = 1; 384 acl_a = acl_get_file(path_a, ACL_TYPE_EXTENDED); 385 #elif ARCHIVE_ACL_FREEBSD_NFS4 386 acl_a = acl_get_file(path_a, ACL_TYPE_NFS4); 387 if (acl_a != NULL) 388 is_nfs4 = 1; 389 #endif 390 if (acl_a == NULL) 391 acl_a = acl_get_file(path_a, ACL_TYPE_ACCESS); 392 failure("acl_get_file() error: %s (%s)", path_a, strerror(errno)); 393 if (assert(acl_a != NULL) == 0) 394 return (-1); 395 #if ARCHIVE_ACL_DARWIN 396 acl_b = acl_get_file(path_b, ACL_TYPE_EXTENDED); 397 #elif ARCHIVE_ACL_FREEBSD_NFS4 398 acl_b = acl_get_file(path_b, ACL_TYPE_NFS4); 399 #endif 400 #if !ARCHIVE_ACL_DARWIN 401 if (acl_b == NULL) { 402 #if ARCHIVE_ACL_FREEBSD_NFS4 403 if (is_nfs4) { 404 acl_free(acl_a); 405 return (0); 406 } 407 #endif 408 acl_b = acl_get_file(path_b, ACL_TYPE_ACCESS); 409 } 410 failure("acl_get_file() error: %s (%s)", path_b, strerror(errno)); 411 if (assert(acl_b != NULL) == 0) { 412 acl_free(acl_a); 413 return (-1); 414 } 415 #endif 416 a = acl_get_entry(acl_a, ACL_FIRST_ENTRY, &aclent_a); 417 if (a == -1) { 418 ret = 0; 419 goto exit_free; 420 } 421 b = acl_get_entry(acl_b, ACL_FIRST_ENTRY, &aclent_b); 422 if (b == -1) { 423 ret = 0; 424 goto exit_free; 425 } 426 #if ARCHIVE_ACL_DARWIN 427 while (a == 0 && b == 0) 428 #else /* FreeBSD, Linux */ 429 while (a == 1 && b == 1) 430 #endif 431 { 432 r = compare_acl_entry(aclent_a, aclent_b, is_nfs4); 433 if (r != 1) { 434 ret = r; 435 goto exit_free; 436 } 437 a = acl_get_entry(acl_a, ACL_NEXT_ENTRY, &aclent_a); 438 b = acl_get_entry(acl_b, ACL_NEXT_ENTRY, &aclent_b); 439 } 440 /* Entry count must match */ 441 if (a != b) 442 ret = 0; 443 #endif /* ARCHIVE_ACL_DARWIN || ARCHIVE_ACL_FREEBSD || ARCHIVE_ACL_LIBACL */ 444 #endif /* !ARCHIVE_ACL_SUNOS */ 445 exit_free: 446 #if ARCHIVE_ACL_SUNOS 447 free(acl_a); 448 free(acl_b); 449 #else 450 acl_free(acl_a); 451 acl_free(acl_b); 452 #endif 453 return (ret); 454 } 455 #endif /* ARCHIVE_ACL_SUPPORT */ 456 457 DEFINE_TEST(test_option_acls) 458 { 459 #if !ARCHIVE_ACL_SUPPORT 460 skipping("ACLs are not supported on this platform"); 461 #else /* ARCHIVE_ACL_SUPPORT */ 462 int acltype, r; 463 464 assertMakeFile("f", 0644, "a"); 465 acltype = setTestAcl("f"); 466 if (acltype == 0) { 467 skipping("Can't write ACLs on the filesystem"); 468 return; 469 } 470 471 /* Archive it with acls */ 472 r = systemf("%s -c --no-mac-metadata --acls -f acls.tar f >acls.out 2>acls.err", testprog); 473 assertEqualInt(r, 0); 474 475 /* Archive it without acls */ 476 r = systemf("%s -c --no-mac-metadata --no-acls -f noacls.tar f >noacls.out 2>noacls.err", testprog); 477 assertEqualInt(r, 0); 478 479 /* Extract acls with acls */ 480 assertMakeDir("acls_acls", 0755); 481 clear_inheritance_flags("acls_acls", acltype); 482 r = systemf("%s -x -C acls_acls --no-same-permissions --acls -f acls.tar >acls_acls.out 2>acls_acls.err", testprog); 483 assertEqualInt(r, 0); 484 r = compare_acls("f", "acls_acls/f"); 485 assertEqualInt(r, 1); 486 487 /* Extract acls without acls */ 488 assertMakeDir("acls_noacls", 0755); 489 clear_inheritance_flags("acls_noacls", acltype); 490 r = systemf("%s -x -C acls_noacls -p --no-acls -f acls.tar >acls_noacls.out 2>acls_noacls.err", testprog); 491 assertEqualInt(r, 0); 492 r = compare_acls("f", "acls_noacls/f"); 493 assertEqualInt(r, 0); 494 495 /* Extract noacls with acls flag */ 496 assertMakeDir("noacls_acls", 0755); 497 clear_inheritance_flags("noacls_acls", acltype); 498 r = systemf("%s -x -C noacls_acls --no-same-permissions --acls -f noacls.tar >noacls_acls.out 2>noacls_acls.err", testprog); 499 assertEqualInt(r, 0); 500 r = compare_acls("f", "noacls_acls/f"); 501 assertEqualInt(r, 0); 502 503 /* Extract noacls with noacls */ 504 assertMakeDir("noacls_noacls", 0755); 505 clear_inheritance_flags("noacls_noacls", acltype); 506 r = systemf("%s -x -C noacls_noacls -p --no-acls -f noacls.tar >noacls_noacls.out 2>noacls_noacls.err", testprog); 507 assertEqualInt(r, 0); 508 r = compare_acls("f", "noacls_noacls/f"); 509 assertEqualInt(r, 0); 510 #endif /* ARCHIVE_ACL_SUPPORT */ 511 } 512