1238909Smm/*- 2238909Smm * Copyright (c) 2003-2010 Tim Kientzle 3238909Smm * All rights reserved. 4238909Smm * 5238909Smm * Redistribution and use in source and binary forms, with or without 6238909Smm * modification, are permitted provided that the following conditions 7238909Smm * are met: 8238909Smm * 1. Redistributions of source code must retain the above copyright 9238909Smm * notice, this list of conditions and the following disclaimer. 10238909Smm * 2. Redistributions in binary form must reproduce the above copyright 11238909Smm * notice, this list of conditions and the following disclaimer in the 12238909Smm * documentation and/or other materials provided with the distribution. 13238909Smm * 14238909Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 15238909Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16238909Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17238909Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 18238909Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19238909Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20238909Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21238909Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22238909Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23238909Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24238909Smm */ 25238909Smm#include "test.h" 26238909Smm__FBSDID("$FreeBSD$"); 27238909Smm 28238909Smm#if defined(__FreeBSD__) && __FreeBSD__ >= 8 29238909Smm#define _ACL_PRIVATE 30238909Smm#include <sys/acl.h> 31238909Smm 32238909Smmstruct myacl_t { 33238909Smm int type; 34238909Smm int permset; 35238909Smm int tag; 36238909Smm int qual; /* GID or UID of user/group, depending on tag. */ 37238909Smm const char *name; /* Name of user/group, depending on tag. */ 38238909Smm}; 39238909Smm 40238909Smmstatic struct myacl_t acls_reg[] = { 41238909Smm /* For this test, we need the file owner to be able to read and write the ACL. */ 42238909Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, 43238909Smm 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, 44238909Smm ARCHIVE_ENTRY_ACL_USER_OBJ, -1, ""}, 45238909Smm 46238909Smm /* An entry for each type. */ 47238909Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE, 48238909Smm ARCHIVE_ENTRY_ACL_USER, 108, "user108" }, 49238909Smm { ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_EXECUTE, 50238909Smm ARCHIVE_ENTRY_ACL_USER, 109, "user109" }, 51238909Smm 52238909Smm /* An entry for each permission. */ 53238909Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE, 54238909Smm ARCHIVE_ENTRY_ACL_USER, 112, "user112" }, 55238909Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_DATA, 56238909Smm ARCHIVE_ENTRY_ACL_USER, 113, "user113" }, 57238909Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_DATA, 58238909Smm ARCHIVE_ENTRY_ACL_USER, 115, "user115" }, 59238909Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_APPEND_DATA, 60238909Smm ARCHIVE_ENTRY_ACL_USER, 117, "user117" }, 61238909Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, 62238909Smm ARCHIVE_ENTRY_ACL_USER, 119, "user119" }, 63238909Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, 64238909Smm ARCHIVE_ENTRY_ACL_USER, 120, "user120" }, 65238909Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, 66238909Smm ARCHIVE_ENTRY_ACL_USER, 122, "user122" }, 67238909Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, 68238909Smm ARCHIVE_ENTRY_ACL_USER, 123, "user123" }, 69238909Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_DELETE, 70238909Smm ARCHIVE_ENTRY_ACL_USER, 124, "user124" }, 71238909Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_ACL, 72238909Smm ARCHIVE_ENTRY_ACL_USER, 125, "user125" }, 73238909Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_ACL, 74238909Smm ARCHIVE_ENTRY_ACL_USER, 126, "user126" }, 75238909Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_OWNER, 76238909Smm ARCHIVE_ENTRY_ACL_USER, 127, "user127" }, 77238909Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_SYNCHRONIZE, 78238909Smm ARCHIVE_ENTRY_ACL_USER, 128, "user128" }, 79238909Smm 80238909Smm /* One entry for each qualifier. */ 81238909Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE, 82238909Smm ARCHIVE_ENTRY_ACL_USER, 135, "user135" }, 83238909Smm// { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE, 84238909Smm// ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" }, 85238909Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE, 86238909Smm ARCHIVE_ENTRY_ACL_GROUP, 136, "group136" }, 87238909Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE, 88238909Smm ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" }, 89238909Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE, 90238909Smm ARCHIVE_ENTRY_ACL_EVERYONE, -1, "" } 91238909Smm}; 92238909Smm 93238909Smm 94238909Smmstatic struct myacl_t acls_dir[] = { 95238909Smm /* For this test, we need to be able to read and write the ACL. */ 96238909Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_ACL, 97238909Smm ARCHIVE_ENTRY_ACL_USER_OBJ, -1, ""}, 98238909Smm 99238909Smm /* An entry for each type. */ 100238909Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, 101238909Smm ARCHIVE_ENTRY_ACL_USER, 101, "user101" }, 102238909Smm { ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, 103238909Smm ARCHIVE_ENTRY_ACL_USER, 102, "user102" }, 104238909Smm 105238909Smm /* An entry for each permission. */ 106238909Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, 107238909Smm ARCHIVE_ENTRY_ACL_USER, 201, "user201" }, 108238909Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_ADD_FILE, 109238909Smm ARCHIVE_ENTRY_ACL_USER, 202, "user202" }, 110238909Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, 111238909Smm ARCHIVE_ENTRY_ACL_USER, 203, "user203" }, 112238909Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, 113238909Smm ARCHIVE_ENTRY_ACL_USER, 204, "user204" }, 114238909Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, 115238909Smm ARCHIVE_ENTRY_ACL_USER, 205, "user205" }, 116238909Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_DELETE_CHILD, 117238909Smm ARCHIVE_ENTRY_ACL_USER, 206, "user206" }, 118238909Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, 119238909Smm ARCHIVE_ENTRY_ACL_USER, 207, "user207" }, 120238909Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, 121238909Smm ARCHIVE_ENTRY_ACL_USER, 208, "user208" }, 122238909Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_DELETE, 123238909Smm ARCHIVE_ENTRY_ACL_USER, 209, "user209" }, 124238909Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_ACL, 125238909Smm ARCHIVE_ENTRY_ACL_USER, 210, "user210" }, 126238909Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_ACL, 127238909Smm ARCHIVE_ENTRY_ACL_USER, 211, "user211" }, 128238909Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_OWNER, 129238909Smm ARCHIVE_ENTRY_ACL_USER, 212, "user212" }, 130238909Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_SYNCHRONIZE, 131238909Smm ARCHIVE_ENTRY_ACL_USER, 213, "user213" }, 132238909Smm 133238909Smm /* One entry with each inheritance value. */ 134238909Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, 135238909Smm ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, 136238909Smm ARCHIVE_ENTRY_ACL_USER, 301, "user301" }, 137238909Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, 138238909Smm ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, 139238909Smm ARCHIVE_ENTRY_ACL_USER, 302, "user302" }, 140238909Smm#if 0 141238909Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, 142238909Smm ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, 143238909Smm ARCHIVE_ENTRY_ACL_USER, 303, "user303" }, 144238909Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, 145238909Smm ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, 146238909Smm ARCHIVE_ENTRY_ACL_USER, 304, "user304" }, 147238909Smm#endif 148238909Smm 149238909Smm#if 0 150238909Smm /* FreeBSD does not support audit entries. */ 151238909Smm { ARCHIVE_ENTRY_ACL_TYPE_AUDIT, 152238909Smm ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, 153238909Smm ARCHIVE_ENTRY_ACL_USER, 401, "user401" }, 154238909Smm { ARCHIVE_ENTRY_ACL_TYPE_AUDIT, 155238909Smm ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, 156238909Smm ARCHIVE_ENTRY_ACL_USER, 402, "user402" }, 157238909Smm#endif 158238909Smm 159238909Smm /* One entry for each qualifier. */ 160238909Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, 161238909Smm ARCHIVE_ENTRY_ACL_USER, 501, "user501" }, 162238909Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, 163238909Smm ARCHIVE_ENTRY_ACL_GROUP, 502, "group502" }, 164238909Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, 165238909Smm ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" }, 166238909Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, 167238909Smm ARCHIVE_ENTRY_ACL_EVERYONE, -1, "" } 168238909Smm}; 169238909Smm 170238909Smmstatic void 171238909Smmset_acls(struct archive_entry *ae, struct myacl_t *acls, int start, int end) 172238909Smm{ 173238909Smm int i; 174238909Smm 175238909Smm archive_entry_acl_clear(ae); 176238909Smm if (start > 0) { 177238909Smm assertEqualInt(ARCHIVE_OK, 178238909Smm archive_entry_acl_add_entry(ae, 179238909Smm acls[0].type, acls[0].permset, acls[0].tag, 180238909Smm acls[0].qual, acls[0].name)); 181238909Smm } 182238909Smm for (i = start; i < end; i++) { 183238909Smm assertEqualInt(ARCHIVE_OK, 184238909Smm archive_entry_acl_add_entry(ae, 185238909Smm acls[i].type, acls[i].permset, acls[i].tag, 186238909Smm acls[i].qual, acls[i].name)); 187238909Smm } 188238909Smm} 189238909Smm 190238909Smmstatic int 191238909Smmacl_permset_to_bitmap(acl_permset_t opaque_ps) 192238909Smm{ 193238909Smm static struct { int machine; int portable; } perms[] = { 194238909Smm {ACL_EXECUTE, ARCHIVE_ENTRY_ACL_EXECUTE}, 195238909Smm {ACL_WRITE, ARCHIVE_ENTRY_ACL_WRITE}, 196238909Smm {ACL_READ, ARCHIVE_ENTRY_ACL_READ}, 197238909Smm {ACL_READ_DATA, ARCHIVE_ENTRY_ACL_READ_DATA}, 198238909Smm {ACL_LIST_DIRECTORY, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY}, 199238909Smm {ACL_WRITE_DATA, ARCHIVE_ENTRY_ACL_WRITE_DATA}, 200238909Smm {ACL_ADD_FILE, ARCHIVE_ENTRY_ACL_ADD_FILE}, 201238909Smm {ACL_APPEND_DATA, ARCHIVE_ENTRY_ACL_APPEND_DATA}, 202238909Smm {ACL_ADD_SUBDIRECTORY, ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY}, 203238909Smm {ACL_READ_NAMED_ATTRS, ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS}, 204238909Smm {ACL_WRITE_NAMED_ATTRS, ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS}, 205238909Smm {ACL_DELETE_CHILD, ARCHIVE_ENTRY_ACL_DELETE_CHILD}, 206238909Smm {ACL_READ_ATTRIBUTES, ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES}, 207238909Smm {ACL_WRITE_ATTRIBUTES, ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES}, 208238909Smm {ACL_DELETE, ARCHIVE_ENTRY_ACL_DELETE}, 209238909Smm {ACL_READ_ACL, ARCHIVE_ENTRY_ACL_READ_ACL}, 210238909Smm {ACL_WRITE_ACL, ARCHIVE_ENTRY_ACL_WRITE_ACL}, 211238909Smm {ACL_WRITE_OWNER, ARCHIVE_ENTRY_ACL_WRITE_OWNER}, 212238909Smm {ACL_SYNCHRONIZE, ARCHIVE_ENTRY_ACL_SYNCHRONIZE} 213238909Smm }; 214238909Smm int i, permset = 0; 215238909Smm 216238909Smm for (i = 0; i < (int)(sizeof(perms)/sizeof(perms[0])); ++i) 217238909Smm if (acl_get_perm_np(opaque_ps, perms[i].machine)) 218238909Smm permset |= perms[i].portable; 219238909Smm return permset; 220238909Smm} 221238909Smm 222238909Smmstatic int 223238909Smmacl_flagset_to_bitmap(acl_flagset_t opaque_fs) 224238909Smm{ 225238909Smm static struct { int machine; int portable; } flags[] = { 226238909Smm {ACL_ENTRY_FILE_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT}, 227238909Smm {ACL_ENTRY_DIRECTORY_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT}, 228238909Smm {ACL_ENTRY_NO_PROPAGATE_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT}, 229238909Smm {ACL_ENTRY_INHERIT_ONLY, ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY}, 230238909Smm }; 231238909Smm int i, flagset = 0; 232238909Smm 233238909Smm for (i = 0; i < (int)(sizeof(flags)/sizeof(flags[0])); ++i) 234238909Smm if (acl_get_flag_np(opaque_fs, flags[i].machine)) 235238909Smm flagset |= flags[i].portable; 236238909Smm return flagset; 237238909Smm} 238238909Smm 239238909Smmstatic int 240238909Smmacl_match(acl_entry_t aclent, struct myacl_t *myacl) 241238909Smm{ 242238909Smm gid_t g, *gp; 243238909Smm uid_t u, *up; 244238909Smm acl_tag_t tag_type; 245238909Smm acl_permset_t opaque_ps; 246238909Smm acl_flagset_t opaque_fs; 247238909Smm int perms; 248238909Smm 249238909Smm acl_get_tag_type(aclent, &tag_type); 250238909Smm 251238909Smm /* translate the silly opaque permset to a bitmap */ 252238909Smm acl_get_permset(aclent, &opaque_ps); 253238909Smm acl_get_flagset_np(aclent, &opaque_fs); 254238909Smm perms = acl_permset_to_bitmap(opaque_ps) | acl_flagset_to_bitmap(opaque_fs); 255238909Smm if (perms != myacl->permset) 256238909Smm return (0); 257238909Smm 258238909Smm switch (tag_type) { 259238909Smm case ACL_USER_OBJ: 260238909Smm if (myacl->tag != ARCHIVE_ENTRY_ACL_USER_OBJ) return (0); 261238909Smm break; 262238909Smm case ACL_USER: 263238909Smm if (myacl->tag != ARCHIVE_ENTRY_ACL_USER) 264238909Smm return (0); 265238909Smm up = acl_get_qualifier(aclent); 266238909Smm u = *up; 267238909Smm acl_free(up); 268238909Smm if ((uid_t)myacl->qual != u) 269238909Smm return (0); 270238909Smm break; 271238909Smm case ACL_GROUP_OBJ: 272238909Smm if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP_OBJ) return (0); 273238909Smm break; 274238909Smm case ACL_GROUP: 275238909Smm if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP) 276238909Smm return (0); 277238909Smm gp = acl_get_qualifier(aclent); 278238909Smm g = *gp; 279238909Smm acl_free(gp); 280238909Smm if ((gid_t)myacl->qual != g) 281238909Smm return (0); 282238909Smm break; 283238909Smm case ACL_MASK: 284238909Smm if (myacl->tag != ARCHIVE_ENTRY_ACL_MASK) return (0); 285238909Smm break; 286238909Smm case ACL_EVERYONE: 287238909Smm if (myacl->tag != ARCHIVE_ENTRY_ACL_EVERYONE) return (0); 288238909Smm break; 289238909Smm } 290238909Smm return (1); 291238909Smm} 292238909Smm 293238909Smmstatic void 294238909Smmcompare_acls(acl_t acl, struct myacl_t *myacls, const char *filename, int start, int end) 295238909Smm{ 296238909Smm int *marker; 297238909Smm int entry_id = ACL_FIRST_ENTRY; 298238909Smm int matched; 299238909Smm int i, n; 300238909Smm acl_entry_t acl_entry; 301238909Smm 302238909Smm n = end - start; 303238909Smm marker = malloc(sizeof(marker[0]) * (n + 1)); 304238909Smm for (i = 0; i < n; i++) 305238909Smm marker[i] = i + start; 306238909Smm /* Always include the first ACE. */ 307238909Smm if (start > 0) { 308238909Smm marker[n] = 0; 309238909Smm ++n; 310238909Smm } 311238909Smm 312238909Smm /* 313238909Smm * Iterate over acls in system acl object, try to match each 314238909Smm * one with an item in the myacls array. 315238909Smm */ 316238909Smm while (1 == acl_get_entry(acl, entry_id, &acl_entry)) { 317238909Smm /* After the first time... */ 318238909Smm entry_id = ACL_NEXT_ENTRY; 319238909Smm 320238909Smm /* Search for a matching entry (tag and qualifier) */ 321238909Smm for (i = 0, matched = 0; i < n && !matched; i++) { 322238909Smm if (acl_match(acl_entry, &myacls[marker[i]])) { 323238909Smm /* We found a match; remove it. */ 324238909Smm marker[i] = marker[n - 1]; 325238909Smm n--; 326238909Smm matched = 1; 327238909Smm } 328238909Smm } 329238909Smm 330238909Smm failure("ACL entry on file %s that shouldn't be there", filename); 331238909Smm assert(matched == 1); 332238909Smm } 333238909Smm 334238909Smm /* Dump entries in the myacls array that weren't in the system acl. */ 335238909Smm for (i = 0; i < n; ++i) { 336238909Smm failure(" ACL entry %d missing from %s: " 337238909Smm "type=%d,permset=%x,tag=%d,qual=%d,name=``%s''\n", 338238909Smm marker[i], filename, 339238909Smm myacls[marker[i]].type, myacls[marker[i]].permset, 340238909Smm myacls[marker[i]].tag, myacls[marker[i]].qual, 341238909Smm myacls[marker[i]].name); 342238909Smm assert(0); /* Record this as a failure. */ 343238909Smm } 344238909Smm free(marker); 345238909Smm} 346238909Smm 347238909Smmstatic void 348238909Smmcompare_entry_acls(struct archive_entry *ae, struct myacl_t *myacls, const char *filename, int start, int end) 349238909Smm{ 350238909Smm int *marker; 351238909Smm int matched; 352238909Smm int i, n; 353238909Smm int type, permset, tag, qual; 354238909Smm const char *name; 355238909Smm 356238909Smm /* Count ACL entries in myacls array and allocate an indirect array. */ 357238909Smm n = end - start; 358238909Smm marker = malloc(sizeof(marker[0]) * (n + 1)); 359238909Smm for (i = 0; i < n; i++) 360238909Smm marker[i] = i + start; 361238909Smm /* Always include the first ACE. */ 362238909Smm if (start > 0) { 363238909Smm marker[n] = 0; 364238909Smm ++n; 365238909Smm } 366238909Smm 367238909Smm /* 368238909Smm * Iterate over acls in entry, try to match each 369238909Smm * one with an item in the myacls array. 370238909Smm */ 371238909Smm assertEqualInt(n, archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_NFS4)); 372238909Smm while (ARCHIVE_OK == archive_entry_acl_next(ae, 373238909Smm ARCHIVE_ENTRY_ACL_TYPE_NFS4, &type, &permset, &tag, &qual, &name)) { 374238909Smm 375238909Smm /* Search for a matching entry (tag and qualifier) */ 376238909Smm for (i = 0, matched = 0; i < n && !matched; i++) { 377238909Smm if (tag == myacls[marker[i]].tag 378238909Smm && qual == myacls[marker[i]].qual 379238909Smm && permset == myacls[marker[i]].permset 380238909Smm && type == myacls[marker[i]].type) { 381238909Smm /* We found a match; remove it. */ 382238909Smm marker[i] = marker[n - 1]; 383238909Smm n--; 384238909Smm matched = 1; 385238909Smm } 386238909Smm } 387238909Smm 388238909Smm failure("ACL entry on file that shouldn't be there: " 389238909Smm "type=%d,permset=%x,tag=%d,qual=%d", 390238909Smm type,permset,tag,qual); 391238909Smm assert(matched == 1); 392238909Smm } 393238909Smm 394238909Smm /* Dump entries in the myacls array that weren't in the system acl. */ 395238909Smm for (i = 0; i < n; ++i) { 396238909Smm failure(" ACL entry %d missing from %s: " 397238909Smm "type=%d,permset=%x,tag=%d,qual=%d,name=``%s''\n", 398238909Smm marker[i], filename, 399238909Smm myacls[marker[i]].type, myacls[marker[i]].permset, 400238909Smm myacls[marker[i]].tag, myacls[marker[i]].qual, 401238909Smm myacls[marker[i]].name); 402238909Smm assert(0); /* Record this as a failure. */ 403238909Smm } 404238909Smm free(marker); 405238909Smm} 406238909Smm#endif 407238909Smm 408238909Smm/* 409238909Smm * Verify ACL restore-to-disk. This test is FreeBSD-specific. 410238909Smm */ 411238909Smm 412238909SmmDEFINE_TEST(test_acl_freebsd_nfs4) 413238909Smm{ 414238909Smm#if !defined(__FreeBSD__) 415238909Smm skipping("FreeBSD-specific NFS4 ACL restore test"); 416238909Smm#elif __FreeBSD__ < 8 417238909Smm skipping("NFS4 ACLs supported only on FreeBSD 8.0 and later"); 418238909Smm#else 419238909Smm char buff[64]; 420238909Smm struct stat st; 421238909Smm struct archive *a; 422238909Smm struct archive_entry *ae; 423238909Smm int i, n; 424238909Smm acl_t acl; 425238909Smm 426238909Smm /* 427238909Smm * First, do a quick manual set/read of ACL data to 428238909Smm * verify that the local filesystem does support ACLs. 429238909Smm * If it doesn't, we'll simply skip the remaining tests. 430238909Smm */ 431238909Smm acl = acl_from_text("owner@:rwxp::allow,group@:rwp:f:allow"); 432238909Smm assert((void *)acl != NULL); 433238909Smm /* Create a test dir and try to set an ACL on it. */ 434238909Smm if (!assertMakeDir("pretest", 0755)) { 435238909Smm acl_free(acl); 436238909Smm return; 437238909Smm } 438238909Smm 439238909Smm n = acl_set_file("pretest", ACL_TYPE_NFS4, acl); 440238909Smm acl_free(acl); 441238909Smm if (n != 0 && errno == EOPNOTSUPP) { 442238909Smm skipping("NFS4 ACL tests require that NFS4 ACLs" 443238909Smm " be enabled on the filesystem"); 444238909Smm return; 445238909Smm } 446238909Smm if (n != 0 && errno == EINVAL) { 447238909Smm skipping("This filesystem does not support NFS4 ACLs"); 448238909Smm return; 449238909Smm } 450238909Smm failure("acl_set_file(): errno = %d (%s)", 451238909Smm errno, strerror(errno)); 452238909Smm assertEqualInt(0, n); 453238909Smm 454238909Smm /* Create a write-to-disk object. */ 455238909Smm assert(NULL != (a = archive_write_disk_new())); 456238909Smm archive_write_disk_set_options(a, 457238909Smm ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_ACL); 458238909Smm 459238909Smm /* Populate an archive entry with some metadata, including ACL info */ 460238909Smm ae = archive_entry_new(); 461238909Smm assert(ae != NULL); 462238909Smm archive_entry_set_pathname(ae, "testall"); 463238909Smm archive_entry_set_filetype(ae, AE_IFREG); 464238909Smm archive_entry_set_perm(ae, 0654); 465238909Smm archive_entry_set_mtime(ae, 123456, 7890); 466238909Smm archive_entry_set_size(ae, 0); 467238909Smm set_acls(ae, acls_reg, 0, (int)(sizeof(acls_reg)/sizeof(acls_reg[0]))); 468238909Smm 469238909Smm /* Write the entry to disk, including ACLs. */ 470238909Smm assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae)); 471238909Smm 472238909Smm /* Likewise for a dir. */ 473238909Smm archive_entry_set_pathname(ae, "dirall"); 474238909Smm archive_entry_set_filetype(ae, AE_IFDIR); 475238909Smm archive_entry_set_perm(ae, 0654); 476238909Smm archive_entry_set_mtime(ae, 123456, 7890); 477238909Smm set_acls(ae, acls_dir, 0, (int)(sizeof(acls_dir)/sizeof(acls_dir[0]))); 478238909Smm assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae)); 479238909Smm 480238909Smm for (i = 0; i < (int)(sizeof(acls_dir)/sizeof(acls_dir[0])); ++i) { 481238909Smm sprintf(buff, "dir%d", i); 482238909Smm archive_entry_set_pathname(ae, buff); 483238909Smm archive_entry_set_filetype(ae, AE_IFDIR); 484238909Smm archive_entry_set_perm(ae, 0654); 485238909Smm archive_entry_set_mtime(ae, 123456 + i, 7891 + i); 486238909Smm set_acls(ae, acls_dir, i, i + 1); 487238909Smm assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae)); 488238909Smm } 489238909Smm 490238909Smm archive_entry_free(ae); 491238909Smm 492238909Smm /* Close the archive. */ 493238909Smm assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a)); 494238909Smm assertEqualInt(ARCHIVE_OK, archive_write_free(a)); 495238909Smm 496238909Smm /* Verify the data on disk. */ 497238909Smm assertEqualInt(0, stat("testall", &st)); 498238909Smm assertEqualInt(st.st_mtime, 123456); 499238909Smm acl = acl_get_file("testall", ACL_TYPE_NFS4); 500238909Smm assert(acl != (acl_t)NULL); 501238909Smm compare_acls(acl, acls_reg, "testall", 0, (int)(sizeof(acls_reg)/sizeof(acls_reg[0]))); 502238909Smm acl_free(acl); 503238909Smm 504238909Smm /* Verify single-permission dirs on disk. */ 505238909Smm for (i = 0; i < (int)(sizeof(acls_dir)/sizeof(acls_dir[0])); ++i) { 506238909Smm sprintf(buff, "dir%d", i); 507238909Smm assertEqualInt(0, stat(buff, &st)); 508238909Smm assertEqualInt(st.st_mtime, 123456 + i); 509238909Smm acl = acl_get_file(buff, ACL_TYPE_NFS4); 510238909Smm assert(acl != (acl_t)NULL); 511238909Smm compare_acls(acl, acls_dir, buff, i, i + 1); 512238909Smm acl_free(acl); 513238909Smm } 514238909Smm 515238909Smm /* Verify "dirall" on disk. */ 516238909Smm assertEqualInt(0, stat("dirall", &st)); 517238909Smm assertEqualInt(st.st_mtime, 123456); 518238909Smm acl = acl_get_file("dirall", ACL_TYPE_NFS4); 519238909Smm assert(acl != (acl_t)NULL); 520238909Smm compare_acls(acl, acls_dir, "dirall", 0, (int)(sizeof(acls_dir)/sizeof(acls_dir[0]))); 521238909Smm acl_free(acl); 522238909Smm 523238909Smm /* Read and compare ACL via archive_read_disk */ 524238909Smm a = archive_read_disk_new(); 525238909Smm assert(a != NULL); 526238909Smm ae = archive_entry_new(); 527238909Smm assert(ae != NULL); 528238909Smm archive_entry_set_pathname(ae, "testall"); 529238909Smm assertEqualInt(ARCHIVE_OK, 530238909Smm archive_read_disk_entry_from_file(a, ae, -1, NULL)); 531238909Smm compare_entry_acls(ae, acls_reg, "testall", 0, (int)(sizeof(acls_reg)/sizeof(acls_reg[0]))); 532238909Smm archive_entry_free(ae); 533238909Smm assertEqualInt(ARCHIVE_OK, archive_read_free(a)); 534238909Smm 535238909Smm /* Read and compare ACL via archive_read_disk */ 536238909Smm a = archive_read_disk_new(); 537238909Smm assert(a != NULL); 538238909Smm ae = archive_entry_new(); 539238909Smm assert(ae != NULL); 540238909Smm archive_entry_set_pathname(ae, "dirall"); 541238909Smm assertEqualInt(ARCHIVE_OK, 542238909Smm archive_read_disk_entry_from_file(a, ae, -1, NULL)); 543238909Smm compare_entry_acls(ae, acls_dir, "dirall", 0, (int)(sizeof(acls_dir)/sizeof(acls_dir[0]))); 544238909Smm archive_entry_free(ae); 545238909Smm assertEqualInt(ARCHIVE_OK, archive_read_free(a)); 546238909Smm#endif 547238909Smm} 548