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 * 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__FBSDID("$FreeBSD$"); 27 28#if defined(__FreeBSD__) && __FreeBSD__ >= 8 29#define _ACL_PRIVATE 30#include <sys/acl.h> 31 32struct myacl_t { 33 int type; 34 int permset; 35 int tag; 36 int qual; /* GID or UID of user/group, depending on tag. */ 37 const char *name; /* Name of user/group, depending on tag. */ 38}; 39 40static struct myacl_t acls_reg[] = { 41 /* For this test, we need the file owner to be able to read and write the ACL. */ 42 { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, 43 ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_READ_ACL | ARCHIVE_ENTRY_ACL_WRITE_ACL | ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS | ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, 44 ARCHIVE_ENTRY_ACL_USER_OBJ, -1, ""}, 45 46 /* An entry for each type. */ 47 { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE, 48 ARCHIVE_ENTRY_ACL_USER, 108, "user108" }, 49 { ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_EXECUTE, 50 ARCHIVE_ENTRY_ACL_USER, 109, "user109" }, 51 52 /* An entry for each permission. */ 53 { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE, 54 ARCHIVE_ENTRY_ACL_USER, 112, "user112" }, 55 { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_DATA, 56 ARCHIVE_ENTRY_ACL_USER, 113, "user113" }, 57 { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_DATA, 58 ARCHIVE_ENTRY_ACL_USER, 115, "user115" }, 59 { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_APPEND_DATA, 60 ARCHIVE_ENTRY_ACL_USER, 117, "user117" }, 61 { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, 62 ARCHIVE_ENTRY_ACL_USER, 119, "user119" }, 63 { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, 64 ARCHIVE_ENTRY_ACL_USER, 120, "user120" }, 65 { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, 66 ARCHIVE_ENTRY_ACL_USER, 122, "user122" }, 67 { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, 68 ARCHIVE_ENTRY_ACL_USER, 123, "user123" }, 69 { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_DELETE, 70 ARCHIVE_ENTRY_ACL_USER, 124, "user124" }, 71 { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_ACL, 72 ARCHIVE_ENTRY_ACL_USER, 125, "user125" }, 73 { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_ACL, 74 ARCHIVE_ENTRY_ACL_USER, 126, "user126" }, 75 { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_OWNER, 76 ARCHIVE_ENTRY_ACL_USER, 127, "user127" }, 77 { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_SYNCHRONIZE, 78 ARCHIVE_ENTRY_ACL_USER, 128, "user128" }, 79 80 /* One entry for each qualifier. */ 81 { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE, 82 ARCHIVE_ENTRY_ACL_USER, 135, "user135" }, 83// { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE, 84// ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" }, 85 { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE, 86 ARCHIVE_ENTRY_ACL_GROUP, 136, "group136" }, 87 { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE, 88 ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" }, 89 { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE, 90 ARCHIVE_ENTRY_ACL_EVERYONE, -1, "" } 91}; 92 93 94static struct myacl_t acls_dir[] = { 95 /* For this test, we need to be able to read and write the ACL. */ 96 { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_ACL, 97 ARCHIVE_ENTRY_ACL_USER_OBJ, -1, ""}, 98 99 /* An entry for each type. */ 100 { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, 101 ARCHIVE_ENTRY_ACL_USER, 101, "user101" }, 102 { ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, 103 ARCHIVE_ENTRY_ACL_USER, 102, "user102" }, 104 105 /* An entry for each permission. */ 106 { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, 107 ARCHIVE_ENTRY_ACL_USER, 201, "user201" }, 108 { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_ADD_FILE, 109 ARCHIVE_ENTRY_ACL_USER, 202, "user202" }, 110 { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, 111 ARCHIVE_ENTRY_ACL_USER, 203, "user203" }, 112 { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, 113 ARCHIVE_ENTRY_ACL_USER, 204, "user204" }, 114 { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, 115 ARCHIVE_ENTRY_ACL_USER, 205, "user205" }, 116 { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_DELETE_CHILD, 117 ARCHIVE_ENTRY_ACL_USER, 206, "user206" }, 118 { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, 119 ARCHIVE_ENTRY_ACL_USER, 207, "user207" }, 120 { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, 121 ARCHIVE_ENTRY_ACL_USER, 208, "user208" }, 122 { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_DELETE, 123 ARCHIVE_ENTRY_ACL_USER, 209, "user209" }, 124 { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_ACL, 125 ARCHIVE_ENTRY_ACL_USER, 210, "user210" }, 126 { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_ACL, 127 ARCHIVE_ENTRY_ACL_USER, 211, "user211" }, 128 { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_OWNER, 129 ARCHIVE_ENTRY_ACL_USER, 212, "user212" }, 130 { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_SYNCHRONIZE, 131 ARCHIVE_ENTRY_ACL_USER, 213, "user213" }, 132 133 /* One entry with each inheritance value. */ 134 { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, 135 ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, 136 ARCHIVE_ENTRY_ACL_USER, 301, "user301" }, 137 { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, 138 ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, 139 ARCHIVE_ENTRY_ACL_USER, 302, "user302" }, 140#if 0 141 { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, 142 ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, 143 ARCHIVE_ENTRY_ACL_USER, 303, "user303" }, 144 { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, 145 ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, 146 ARCHIVE_ENTRY_ACL_USER, 304, "user304" }, 147#endif 148 149#if 0 150 /* FreeBSD does not support audit entries. */ 151 { ARCHIVE_ENTRY_ACL_TYPE_AUDIT, 152 ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, 153 ARCHIVE_ENTRY_ACL_USER, 401, "user401" }, 154 { ARCHIVE_ENTRY_ACL_TYPE_AUDIT, 155 ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, 156 ARCHIVE_ENTRY_ACL_USER, 402, "user402" }, 157#endif 158 159 /* One entry for each qualifier. */ 160 { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, 161 ARCHIVE_ENTRY_ACL_USER, 501, "user501" }, 162 { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, 163 ARCHIVE_ENTRY_ACL_GROUP, 502, "group502" }, 164 { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, 165 ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" }, 166 { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, 167 ARCHIVE_ENTRY_ACL_EVERYONE, -1, "" } 168}; 169 170static void 171set_acls(struct archive_entry *ae, struct myacl_t *acls, int start, int end) 172{ 173 int i; 174 175 archive_entry_acl_clear(ae); 176 if (start > 0) { 177 assertEqualInt(ARCHIVE_OK, 178 archive_entry_acl_add_entry(ae, 179 acls[0].type, acls[0].permset, acls[0].tag, 180 acls[0].qual, acls[0].name)); 181 } 182 for (i = start; i < end; i++) { 183 assertEqualInt(ARCHIVE_OK, 184 archive_entry_acl_add_entry(ae, 185 acls[i].type, acls[i].permset, acls[i].tag, 186 acls[i].qual, acls[i].name)); 187 } 188} 189 190static int 191acl_permset_to_bitmap(acl_permset_t opaque_ps) 192{ 193 static struct { int machine; int portable; } perms[] = { 194 {ACL_EXECUTE, ARCHIVE_ENTRY_ACL_EXECUTE}, 195 {ACL_WRITE, ARCHIVE_ENTRY_ACL_WRITE}, 196 {ACL_READ, ARCHIVE_ENTRY_ACL_READ}, 197 {ACL_READ_DATA, ARCHIVE_ENTRY_ACL_READ_DATA}, 198 {ACL_LIST_DIRECTORY, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY}, 199 {ACL_WRITE_DATA, ARCHIVE_ENTRY_ACL_WRITE_DATA}, 200 {ACL_ADD_FILE, ARCHIVE_ENTRY_ACL_ADD_FILE}, 201 {ACL_APPEND_DATA, ARCHIVE_ENTRY_ACL_APPEND_DATA}, 202 {ACL_ADD_SUBDIRECTORY, ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY}, 203 {ACL_READ_NAMED_ATTRS, ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS}, 204 {ACL_WRITE_NAMED_ATTRS, ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS}, 205 {ACL_DELETE_CHILD, ARCHIVE_ENTRY_ACL_DELETE_CHILD}, 206 {ACL_READ_ATTRIBUTES, ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES}, 207 {ACL_WRITE_ATTRIBUTES, ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES}, 208 {ACL_DELETE, ARCHIVE_ENTRY_ACL_DELETE}, 209 {ACL_READ_ACL, ARCHIVE_ENTRY_ACL_READ_ACL}, 210 {ACL_WRITE_ACL, ARCHIVE_ENTRY_ACL_WRITE_ACL}, 211 {ACL_WRITE_OWNER, ARCHIVE_ENTRY_ACL_WRITE_OWNER}, 212 {ACL_SYNCHRONIZE, ARCHIVE_ENTRY_ACL_SYNCHRONIZE} 213 }; 214 int i, permset = 0; 215 216 for (i = 0; i < (int)(sizeof(perms)/sizeof(perms[0])); ++i) 217 if (acl_get_perm_np(opaque_ps, perms[i].machine)) 218 permset |= perms[i].portable; 219 return permset; 220} 221 222static int 223acl_flagset_to_bitmap(acl_flagset_t opaque_fs) 224{ 225 static struct { int machine; int portable; } flags[] = { 226 {ACL_ENTRY_FILE_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT}, 227 {ACL_ENTRY_DIRECTORY_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT}, 228 {ACL_ENTRY_NO_PROPAGATE_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT}, 229 {ACL_ENTRY_INHERIT_ONLY, ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY}, 230 }; 231 int i, flagset = 0; 232 233 for (i = 0; i < (int)(sizeof(flags)/sizeof(flags[0])); ++i) 234 if (acl_get_flag_np(opaque_fs, flags[i].machine)) 235 flagset |= flags[i].portable; 236 return flagset; 237} 238 239static int 240acl_match(acl_entry_t aclent, struct myacl_t *myacl) 241{ 242 gid_t g, *gp; 243 uid_t u, *up; 244 acl_tag_t tag_type; 245 acl_permset_t opaque_ps; 246 acl_flagset_t opaque_fs; 247 int perms; 248 249 acl_get_tag_type(aclent, &tag_type); 250 251 /* translate the silly opaque permset to a bitmap */ 252 acl_get_permset(aclent, &opaque_ps); 253 acl_get_flagset_np(aclent, &opaque_fs); 254 perms = acl_permset_to_bitmap(opaque_ps) | acl_flagset_to_bitmap(opaque_fs); 255 if (perms != myacl->permset) 256 return (0); 257 258 switch (tag_type) { 259 case ACL_USER_OBJ: 260 if (myacl->tag != ARCHIVE_ENTRY_ACL_USER_OBJ) return (0); 261 break; 262 case ACL_USER: 263 if (myacl->tag != ARCHIVE_ENTRY_ACL_USER) 264 return (0); 265 up = acl_get_qualifier(aclent); 266 u = *up; 267 acl_free(up); 268 if ((uid_t)myacl->qual != u) 269 return (0); 270 break; 271 case ACL_GROUP_OBJ: 272 if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP_OBJ) return (0); 273 break; 274 case ACL_GROUP: 275 if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP) 276 return (0); 277 gp = acl_get_qualifier(aclent); 278 g = *gp; 279 acl_free(gp); 280 if ((gid_t)myacl->qual != g) 281 return (0); 282 break; 283 case ACL_MASK: 284 if (myacl->tag != ARCHIVE_ENTRY_ACL_MASK) return (0); 285 break; 286 case ACL_EVERYONE: 287 if (myacl->tag != ARCHIVE_ENTRY_ACL_EVERYONE) return (0); 288 break; 289 } 290 return (1); 291} 292 293static void 294compare_acls(acl_t acl, struct myacl_t *myacls, const char *filename, int start, int end) 295{ 296 int *marker; 297 int entry_id = ACL_FIRST_ENTRY; 298 int matched; 299 int i, n; 300 acl_entry_t acl_entry; 301 302 n = end - start; 303 marker = malloc(sizeof(marker[0]) * (n + 1)); 304 for (i = 0; i < n; i++) 305 marker[i] = i + start; 306 /* Always include the first ACE. */ 307 if (start > 0) { 308 marker[n] = 0; 309 ++n; 310 } 311 312 /* 313 * Iterate over acls in system acl object, try to match each 314 * one with an item in the myacls array. 315 */ 316 while (1 == acl_get_entry(acl, entry_id, &acl_entry)) { 317 /* After the first time... */ 318 entry_id = ACL_NEXT_ENTRY; 319 320 /* Search for a matching entry (tag and qualifier) */ 321 for (i = 0, matched = 0; i < n && !matched; i++) { 322 if (acl_match(acl_entry, &myacls[marker[i]])) { 323 /* We found a match; remove it. */ 324 marker[i] = marker[n - 1]; 325 n--; 326 matched = 1; 327 } 328 } 329 330 failure("ACL entry on file %s that shouldn't be there", filename); 331 assert(matched == 1); 332 } 333 334 /* Dump entries in the myacls array that weren't in the system acl. */ 335 for (i = 0; i < n; ++i) { 336 failure(" ACL entry %d missing from %s: " 337 "type=%d,permset=%x,tag=%d,qual=%d,name=``%s''\n", 338 marker[i], filename, 339 myacls[marker[i]].type, myacls[marker[i]].permset, 340 myacls[marker[i]].tag, myacls[marker[i]].qual, 341 myacls[marker[i]].name); 342 assert(0); /* Record this as a failure. */ 343 } 344 free(marker); 345} 346 347static void 348compare_entry_acls(struct archive_entry *ae, struct myacl_t *myacls, const char *filename, int start, int end) 349{ 350 int *marker; 351 int matched; 352 int i, n; 353 int type, permset, tag, qual; 354 const char *name; 355 356 /* Count ACL entries in myacls array and allocate an indirect array. */ 357 n = end - start; 358 marker = malloc(sizeof(marker[0]) * (n + 1)); 359 for (i = 0; i < n; i++) 360 marker[i] = i + start; 361 /* Always include the first ACE. */ 362 if (start > 0) { 363 marker[n] = 0; 364 ++n; 365 } 366 367 /* 368 * Iterate over acls in entry, try to match each 369 * one with an item in the myacls array. 370 */ 371 assertEqualInt(n, archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_NFS4)); 372 while (ARCHIVE_OK == archive_entry_acl_next(ae, 373 ARCHIVE_ENTRY_ACL_TYPE_NFS4, &type, &permset, &tag, &qual, &name)) { 374 375 /* Search for a matching entry (tag and qualifier) */ 376 for (i = 0, matched = 0; i < n && !matched; i++) { 377 if (tag == myacls[marker[i]].tag 378 && qual == myacls[marker[i]].qual 379 && permset == myacls[marker[i]].permset 380 && type == myacls[marker[i]].type) { 381 /* We found a match; remove it. */ 382 marker[i] = marker[n - 1]; 383 n--; 384 matched = 1; 385 } 386 } 387 388 failure("ACL entry on file that shouldn't be there: " 389 "type=%d,permset=%x,tag=%d,qual=%d", 390 type,permset,tag,qual); 391 assert(matched == 1); 392 } 393 394 /* Dump entries in the myacls array that weren't in the system acl. */ 395 for (i = 0; i < n; ++i) { 396 failure(" ACL entry %d missing from %s: " 397 "type=%d,permset=%x,tag=%d,qual=%d,name=``%s''\n", 398 marker[i], filename, 399 myacls[marker[i]].type, myacls[marker[i]].permset, 400 myacls[marker[i]].tag, myacls[marker[i]].qual, 401 myacls[marker[i]].name); 402 assert(0); /* Record this as a failure. */ 403 } 404 free(marker); 405} 406#endif 407 408/* 409 * Verify ACL restore-to-disk. This test is FreeBSD-specific. 410 */ 411 412DEFINE_TEST(test_acl_freebsd_nfs4) 413{ 414#if !defined(__FreeBSD__) 415 skipping("FreeBSD-specific NFS4 ACL restore test"); 416#elif __FreeBSD__ < 8 417 skipping("NFS4 ACLs supported only on FreeBSD 8.0 and later"); 418#else 419 char buff[64]; 420 struct stat st; 421 struct archive *a; 422 struct archive_entry *ae; 423 int i, n; 424 acl_t acl; 425 426 /* 427 * First, do a quick manual set/read of ACL data to 428 * verify that the local filesystem does support ACLs. 429 * If it doesn't, we'll simply skip the remaining tests. 430 */ 431 acl = acl_from_text("owner@:rwxp::allow,group@:rwp:f:allow"); 432 assert((void *)acl != NULL); 433 /* Create a test dir and try to set an ACL on it. */ 434 if (!assertMakeDir("pretest", 0755)) { 435 acl_free(acl); 436 return; 437 } 438 439 n = acl_set_file("pretest", ACL_TYPE_NFS4, acl); 440 acl_free(acl); 441 if (n != 0 && errno == EOPNOTSUPP) { 442 skipping("NFS4 ACL tests require that NFS4 ACLs" 443 " be enabled on the filesystem"); 444 return; 445 } 446 if (n != 0 && errno == EINVAL) { 447 skipping("This filesystem does not support NFS4 ACLs"); 448 return; 449 } 450 failure("acl_set_file(): errno = %d (%s)", 451 errno, strerror(errno)); 452 assertEqualInt(0, n); 453 454 /* Create a write-to-disk object. */ 455 assert(NULL != (a = archive_write_disk_new())); 456 archive_write_disk_set_options(a, 457 ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_ACL); 458 459 /* Populate an archive entry with some metadata, including ACL info */ 460 ae = archive_entry_new(); 461 assert(ae != NULL); 462 archive_entry_set_pathname(ae, "testall"); 463 archive_entry_set_filetype(ae, AE_IFREG); 464 archive_entry_set_perm(ae, 0654); 465 archive_entry_set_mtime(ae, 123456, 7890); 466 archive_entry_set_size(ae, 0); 467 set_acls(ae, acls_reg, 0, (int)(sizeof(acls_reg)/sizeof(acls_reg[0]))); 468 469 /* Write the entry to disk, including ACLs. */ 470 assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae)); 471 472 /* Likewise for a dir. */ 473 archive_entry_set_pathname(ae, "dirall"); 474 archive_entry_set_filetype(ae, AE_IFDIR); 475 archive_entry_set_perm(ae, 0654); 476 archive_entry_set_mtime(ae, 123456, 7890); 477 set_acls(ae, acls_dir, 0, (int)(sizeof(acls_dir)/sizeof(acls_dir[0]))); 478 assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae)); 479 480 for (i = 0; i < (int)(sizeof(acls_dir)/sizeof(acls_dir[0])); ++i) { 481 sprintf(buff, "dir%d", i); 482 archive_entry_set_pathname(ae, buff); 483 archive_entry_set_filetype(ae, AE_IFDIR); 484 archive_entry_set_perm(ae, 0654); 485 archive_entry_set_mtime(ae, 123456 + i, 7891 + i); 486 set_acls(ae, acls_dir, i, i + 1); 487 assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae)); 488 } 489 490 archive_entry_free(ae); 491 492 /* Close the archive. */ 493 assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a)); 494 assertEqualInt(ARCHIVE_OK, archive_write_free(a)); 495 496 /* Verify the data on disk. */ 497 assertEqualInt(0, stat("testall", &st)); 498 assertEqualInt(st.st_mtime, 123456); 499 acl = acl_get_file("testall", ACL_TYPE_NFS4); 500 assert(acl != (acl_t)NULL); 501 compare_acls(acl, acls_reg, "testall", 0, (int)(sizeof(acls_reg)/sizeof(acls_reg[0]))); 502 acl_free(acl); 503 504 /* Verify single-permission dirs on disk. */ 505 for (i = 0; i < (int)(sizeof(acls_dir)/sizeof(acls_dir[0])); ++i) { 506 sprintf(buff, "dir%d", i); 507 assertEqualInt(0, stat(buff, &st)); 508 assertEqualInt(st.st_mtime, 123456 + i); 509 acl = acl_get_file(buff, ACL_TYPE_NFS4); 510 assert(acl != (acl_t)NULL); 511 compare_acls(acl, acls_dir, buff, i, i + 1); 512 acl_free(acl); 513 } 514 515 /* Verify "dirall" on disk. */ 516 assertEqualInt(0, stat("dirall", &st)); 517 assertEqualInt(st.st_mtime, 123456); 518 acl = acl_get_file("dirall", ACL_TYPE_NFS4); 519 assert(acl != (acl_t)NULL); 520 compare_acls(acl, acls_dir, "dirall", 0, (int)(sizeof(acls_dir)/sizeof(acls_dir[0]))); 521 acl_free(acl); 522 523 /* Read and compare ACL via archive_read_disk */ 524 a = archive_read_disk_new(); 525 assert(a != NULL); 526 ae = archive_entry_new(); 527 assert(ae != NULL); 528 archive_entry_set_pathname(ae, "testall"); 529 assertEqualInt(ARCHIVE_OK, 530 archive_read_disk_entry_from_file(a, ae, -1, NULL)); 531 compare_entry_acls(ae, acls_reg, "testall", 0, (int)(sizeof(acls_reg)/sizeof(acls_reg[0]))); 532 archive_entry_free(ae); 533 assertEqualInt(ARCHIVE_OK, archive_read_free(a)); 534 535 /* Read and compare ACL via archive_read_disk */ 536 a = archive_read_disk_new(); 537 assert(a != NULL); 538 ae = archive_entry_new(); 539 assert(ae != NULL); 540 archive_entry_set_pathname(ae, "dirall"); 541 assertEqualInt(ARCHIVE_OK, 542 archive_read_disk_entry_from_file(a, ae, -1, NULL)); 543 compare_entry_acls(ae, acls_dir, "dirall", 0, (int)(sizeof(acls_dir)/sizeof(acls_dir[0]))); 544 archive_entry_free(ae); 545 assertEqualInt(ARCHIVE_OK, archive_read_free(a)); 546#endif 547} 548