1caf54c4fSMartin Matuska /*- 2caf54c4fSMartin Matuska * Copyright (c) 2003-2007 Tim Kientzle 3caf54c4fSMartin Matuska * All rights reserved. 4caf54c4fSMartin Matuska * 5caf54c4fSMartin Matuska * Redistribution and use in source and binary forms, with or without 6caf54c4fSMartin Matuska * modification, are permitted provided that the following conditions 7caf54c4fSMartin Matuska * are met: 8caf54c4fSMartin Matuska * 1. Redistributions of source code must retain the above copyright 9caf54c4fSMartin Matuska * notice, this list of conditions and the following disclaimer. 10caf54c4fSMartin Matuska * 2. Redistributions in binary form must reproduce the above copyright 11caf54c4fSMartin Matuska * notice, this list of conditions and the following disclaimer in the 12caf54c4fSMartin Matuska * documentation and/or other materials provided with the distribution. 13caf54c4fSMartin Matuska * 14caf54c4fSMartin Matuska * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 15caf54c4fSMartin Matuska * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16caf54c4fSMartin Matuska * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17caf54c4fSMartin Matuska * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 18caf54c4fSMartin Matuska * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19caf54c4fSMartin Matuska * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20caf54c4fSMartin Matuska * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21caf54c4fSMartin Matuska * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22caf54c4fSMartin Matuska * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23caf54c4fSMartin Matuska * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24caf54c4fSMartin Matuska */ 25caf54c4fSMartin Matuska #include "test.h" 266c22d9efSMartin Matuska __FBSDID("$FreeBSD$"); 27caf54c4fSMartin Matuska 28caf54c4fSMartin Matuska /* 29caf54c4fSMartin Matuska * Exercise the system-independent portion of the ACL support. 30caf54c4fSMartin Matuska * Check that pax archive can save and restore ACL data. 31caf54c4fSMartin Matuska * 32caf54c4fSMartin Matuska * This should work on all systems, regardless of whether local 33caf54c4fSMartin Matuska * filesystems support ACLs or not. 34caf54c4fSMartin Matuska */ 35caf54c4fSMartin Matuska 36caf54c4fSMartin Matuska static unsigned char buff[16384]; 37caf54c4fSMartin Matuska 38caf54c4fSMartin Matuska struct acl_t { 39caf54c4fSMartin Matuska int type; /* Type of ACL: "access" or "default" */ 40caf54c4fSMartin Matuska int permset; /* Permissions for this class of users. */ 41caf54c4fSMartin Matuska int tag; /* Owner, User, Owning group, group, other, etc. */ 42caf54c4fSMartin Matuska int qual; /* GID or UID of user/group, depending on tag. */ 43caf54c4fSMartin Matuska const char *name; /* Name of user/group, depending on tag. */ 44caf54c4fSMartin Matuska }; 45caf54c4fSMartin Matuska 46caf54c4fSMartin Matuska static struct acl_t acls0[] = { 47caf54c4fSMartin Matuska { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_EXECUTE, 48caf54c4fSMartin Matuska ARCHIVE_ENTRY_ACL_USER_OBJ, 0, "" }, 49caf54c4fSMartin Matuska { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_READ, 50caf54c4fSMartin Matuska ARCHIVE_ENTRY_ACL_GROUP_OBJ, 0, "" }, 51caf54c4fSMartin Matuska { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_WRITE, 52caf54c4fSMartin Matuska ARCHIVE_ENTRY_ACL_OTHER, 0, "" }, 53caf54c4fSMartin Matuska }; 54caf54c4fSMartin Matuska 55caf54c4fSMartin Matuska static struct acl_t acls1[] = { 56caf54c4fSMartin Matuska { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_EXECUTE, 57caf54c4fSMartin Matuska ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" }, 58caf54c4fSMartin Matuska { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_READ, 59caf54c4fSMartin Matuska ARCHIVE_ENTRY_ACL_USER, 77, "user77" }, 60caf54c4fSMartin Matuska { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_READ, 61caf54c4fSMartin Matuska ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" }, 62caf54c4fSMartin Matuska { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_WRITE, 63caf54c4fSMartin Matuska ARCHIVE_ENTRY_ACL_OTHER, -1, "" }, 64caf54c4fSMartin Matuska }; 65caf54c4fSMartin Matuska 66caf54c4fSMartin Matuska static struct acl_t acls2[] = { 67caf54c4fSMartin Matuska { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_EXECUTE | ARCHIVE_ENTRY_ACL_READ, 68caf54c4fSMartin Matuska ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" }, 69caf54c4fSMartin Matuska { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_READ, 70caf54c4fSMartin Matuska ARCHIVE_ENTRY_ACL_USER, 77, "user77" }, 71caf54c4fSMartin Matuska { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 0, 72caf54c4fSMartin Matuska ARCHIVE_ENTRY_ACL_USER, 78, "user78" }, 73caf54c4fSMartin Matuska { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_READ, 74caf54c4fSMartin Matuska ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" }, 75caf54c4fSMartin Matuska { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 0007, 76caf54c4fSMartin Matuska ARCHIVE_ENTRY_ACL_GROUP, 78, "group78" }, 77caf54c4fSMartin Matuska { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_WRITE | ARCHIVE_ENTRY_ACL_EXECUTE, 78caf54c4fSMartin Matuska ARCHIVE_ENTRY_ACL_OTHER, -1, "" }, 79caf54c4fSMartin Matuska }; 80caf54c4fSMartin Matuska 81caf54c4fSMartin Matuska static void 82caf54c4fSMartin Matuska set_acls(struct archive_entry *ae, struct acl_t *acls, int n) 83caf54c4fSMartin Matuska { 84caf54c4fSMartin Matuska int i; 85caf54c4fSMartin Matuska 86caf54c4fSMartin Matuska archive_entry_acl_clear(ae); 87caf54c4fSMartin Matuska for (i = 0; i < n; i++) { 88caf54c4fSMartin Matuska archive_entry_acl_add_entry(ae, 89caf54c4fSMartin Matuska acls[i].type, acls[i].permset, acls[i].tag, acls[i].qual, 90caf54c4fSMartin Matuska acls[i].name); 91caf54c4fSMartin Matuska } 92caf54c4fSMartin Matuska } 93caf54c4fSMartin Matuska 94caf54c4fSMartin Matuska static int 95caf54c4fSMartin Matuska acl_match(struct acl_t *acl, int type, int permset, int tag, int qual, const char *name) 96caf54c4fSMartin Matuska { 97caf54c4fSMartin Matuska if (type != acl->type) 98caf54c4fSMartin Matuska return (0); 99caf54c4fSMartin Matuska if (permset != acl->permset) 100caf54c4fSMartin Matuska return (0); 101caf54c4fSMartin Matuska if (tag != acl->tag) 102caf54c4fSMartin Matuska return (0); 103caf54c4fSMartin Matuska if (tag == ARCHIVE_ENTRY_ACL_USER_OBJ) 104caf54c4fSMartin Matuska return (1); 105caf54c4fSMartin Matuska if (tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ) 106caf54c4fSMartin Matuska return (1); 107caf54c4fSMartin Matuska if (tag == ARCHIVE_ENTRY_ACL_OTHER) 108caf54c4fSMartin Matuska return (1); 109caf54c4fSMartin Matuska if (qual != acl->qual) 110caf54c4fSMartin Matuska return (0); 111caf54c4fSMartin Matuska if (name == NULL) 112caf54c4fSMartin Matuska return (acl->name == NULL || acl->name[0] == '\0'); 113caf54c4fSMartin Matuska if (acl->name == NULL) 114caf54c4fSMartin Matuska return (name == NULL || name[0] == '\0'); 115caf54c4fSMartin Matuska return (0 == strcmp(name, acl->name)); 116caf54c4fSMartin Matuska } 117caf54c4fSMartin Matuska 118caf54c4fSMartin Matuska static void 119caf54c4fSMartin Matuska compare_acls(struct archive_entry *ae, struct acl_t *acls, int n, int mode) 120caf54c4fSMartin Matuska { 121caf54c4fSMartin Matuska int *marker = malloc(sizeof(marker[0]) * n); 122caf54c4fSMartin Matuska int i; 123caf54c4fSMartin Matuska int r; 124caf54c4fSMartin Matuska int type, permset, tag, qual; 125caf54c4fSMartin Matuska int matched; 126caf54c4fSMartin Matuska const char *name; 127caf54c4fSMartin Matuska 128caf54c4fSMartin Matuska for (i = 0; i < n; i++) 129caf54c4fSMartin Matuska marker[i] = i; 130caf54c4fSMartin Matuska 131caf54c4fSMartin Matuska while (0 == (r = archive_entry_acl_next(ae, 132caf54c4fSMartin Matuska ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 133caf54c4fSMartin Matuska &type, &permset, &tag, &qual, &name))) { 134caf54c4fSMartin Matuska for (i = 0, matched = 0; i < n && !matched; i++) { 135caf54c4fSMartin Matuska if (acl_match(&acls[marker[i]], type, permset, 136caf54c4fSMartin Matuska tag, qual, name)) { 137caf54c4fSMartin Matuska /* We found a match; remove it. */ 138caf54c4fSMartin Matuska marker[i] = marker[n - 1]; 139caf54c4fSMartin Matuska n--; 140caf54c4fSMartin Matuska matched = 1; 141caf54c4fSMartin Matuska } 142caf54c4fSMartin Matuska } 143caf54c4fSMartin Matuska if (tag == ARCHIVE_ENTRY_ACL_USER_OBJ) { 144caf54c4fSMartin Matuska if (!matched) printf("No match for user_obj perm\n"); 145caf54c4fSMartin Matuska failure("USER_OBJ permset (%02o) != user mode (%02o)", 146caf54c4fSMartin Matuska permset, 07 & (mode >> 6)); 147caf54c4fSMartin Matuska assert((permset << 6) == (mode & 0700)); 148caf54c4fSMartin Matuska } else if (tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ) { 149caf54c4fSMartin Matuska if (!matched) printf("No match for group_obj perm\n"); 150caf54c4fSMartin Matuska failure("GROUP_OBJ permset %02o != group mode %02o", 151caf54c4fSMartin Matuska permset, 07 & (mode >> 3)); 152caf54c4fSMartin Matuska assert((permset << 3) == (mode & 0070)); 153caf54c4fSMartin Matuska } else if (tag == ARCHIVE_ENTRY_ACL_OTHER) { 154caf54c4fSMartin Matuska if (!matched) printf("No match for other perm\n"); 155caf54c4fSMartin Matuska failure("OTHER permset (%02o) != other mode (%02o)", 156caf54c4fSMartin Matuska permset, mode & 07); 157caf54c4fSMartin Matuska assert((permset << 0) == (mode & 0007)); 158caf54c4fSMartin Matuska } else { 159caf54c4fSMartin Matuska failure("Could not find match for ACL " 160caf54c4fSMartin Matuska "(type=%d,permset=%d,tag=%d,qual=%d,name=``%s'')", 161caf54c4fSMartin Matuska type, permset, tag, qual, name); 162caf54c4fSMartin Matuska assert(matched == 1); 163caf54c4fSMartin Matuska } 164caf54c4fSMartin Matuska } 165caf54c4fSMartin Matuska assertEqualInt(ARCHIVE_EOF, r); 1666c95142eSMartin Matuska assert((mode_t)(mode & 0777) == (archive_entry_mode(ae) & 0777)); 167caf54c4fSMartin Matuska failure("Could not find match for ACL " 168caf54c4fSMartin Matuska "(type=%d,permset=%d,tag=%d,qual=%d,name=``%s'')", 169caf54c4fSMartin Matuska acls[marker[0]].type, acls[marker[0]].permset, 170caf54c4fSMartin Matuska acls[marker[0]].tag, acls[marker[0]].qual, acls[marker[0]].name); 171caf54c4fSMartin Matuska assert(n == 0); /* Number of ACLs not matched should == 0 */ 172caf54c4fSMartin Matuska free(marker); 173caf54c4fSMartin Matuska } 174caf54c4fSMartin Matuska 175caf54c4fSMartin Matuska DEFINE_TEST(test_acl_pax) 176caf54c4fSMartin Matuska { 177caf54c4fSMartin Matuska struct archive *a; 178caf54c4fSMartin Matuska struct archive_entry *ae; 179caf54c4fSMartin Matuska size_t used; 180caf54c4fSMartin Matuska FILE *f; 1816c95142eSMartin Matuska void *reference; 1826c95142eSMartin Matuska size_t reference_size; 183caf54c4fSMartin Matuska 184caf54c4fSMartin Matuska /* Write an archive to memory. */ 185caf54c4fSMartin Matuska assert(NULL != (a = archive_write_new())); 186caf54c4fSMartin Matuska assertA(0 == archive_write_set_format_pax(a)); 187caf54c4fSMartin Matuska assertA(0 == archive_write_set_compression_none(a)); 188caf54c4fSMartin Matuska assertA(0 == archive_write_set_bytes_per_block(a, 1)); 189caf54c4fSMartin Matuska assertA(0 == archive_write_set_bytes_in_last_block(a, 1)); 190caf54c4fSMartin Matuska assertA(0 == archive_write_open_memory(a, buff, sizeof(buff), &used)); 191caf54c4fSMartin Matuska 192caf54c4fSMartin Matuska /* Write a series of files to the archive with different ACL info. */ 193caf54c4fSMartin Matuska 194caf54c4fSMartin Matuska /* Create a simple archive_entry. */ 195caf54c4fSMartin Matuska assert((ae = archive_entry_new()) != NULL); 196caf54c4fSMartin Matuska archive_entry_set_pathname(ae, "file"); 197caf54c4fSMartin Matuska archive_entry_set_mode(ae, S_IFREG | 0777); 198caf54c4fSMartin Matuska 199caf54c4fSMartin Matuska /* Basic owner/owning group should just update mode bits. */ 200caf54c4fSMartin Matuska set_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0])); 201caf54c4fSMartin Matuska assertA(0 == archive_write_header(a, ae)); 202caf54c4fSMartin Matuska 203caf54c4fSMartin Matuska /* With any extended ACL entry, we should read back a full set. */ 204caf54c4fSMartin Matuska set_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0])); 205caf54c4fSMartin Matuska assertA(0 == archive_write_header(a, ae)); 206caf54c4fSMartin Matuska 207caf54c4fSMartin Matuska 208caf54c4fSMartin Matuska /* A more extensive set of ACLs. */ 209caf54c4fSMartin Matuska set_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0])); 210caf54c4fSMartin Matuska assertA(0 == archive_write_header(a, ae)); 211caf54c4fSMartin Matuska 212caf54c4fSMartin Matuska /* 213caf54c4fSMartin Matuska * Check that clearing ACLs gets rid of them all by repeating 214caf54c4fSMartin Matuska * the first test. 215caf54c4fSMartin Matuska */ 216caf54c4fSMartin Matuska set_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0])); 217caf54c4fSMartin Matuska assertA(0 == archive_write_header(a, ae)); 218caf54c4fSMartin Matuska archive_entry_free(ae); 219caf54c4fSMartin Matuska 220caf54c4fSMartin Matuska /* Close out the archive. */ 2216c95142eSMartin Matuska assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a)); 2226c95142eSMartin Matuska assertEqualInt(ARCHIVE_OK, archive_write_free(a)); 223caf54c4fSMartin Matuska 224caf54c4fSMartin Matuska /* Write out the data we generated to a file for manual inspection. */ 225caf54c4fSMartin Matuska assert(NULL != (f = fopen("testout", "wb"))); 226caf54c4fSMartin Matuska assertEqualInt(used, (size_t)fwrite(buff, 1, (unsigned int)used, f)); 227caf54c4fSMartin Matuska fclose(f); 228caf54c4fSMartin Matuska 229caf54c4fSMartin Matuska /* Write out the reference data to a file for manual inspection. */ 2306c95142eSMartin Matuska extract_reference_file("test_acl_pax.tar"); 2316c95142eSMartin Matuska reference = slurpfile(&reference_size, "test_acl_pax.tar"); 232caf54c4fSMartin Matuska 233caf54c4fSMartin Matuska /* Assert that the generated data matches the built-in reference data.*/ 2346c95142eSMartin Matuska failure("Generated pax archive does not match reference; compare 'testout' to 'test_acl_pax.tar' reference file."); 2356c95142eSMartin Matuska assertEqualMem(buff, reference, reference_size); 2366c95142eSMartin Matuska failure("Generated pax archive does not match reference; compare 'testout' to 'test_acl_pax.tar' reference file."); 2376c95142eSMartin Matuska assertEqualInt((int)used, reference_size); 2386c95142eSMartin Matuska free(reference); 239caf54c4fSMartin Matuska 240caf54c4fSMartin Matuska /* Read back each entry and check that the ACL data is right. */ 241caf54c4fSMartin Matuska assert(NULL != (a = archive_read_new())); 242caf54c4fSMartin Matuska assertA(0 == archive_read_support_format_all(a)); 2436c95142eSMartin Matuska assertA(0 == archive_read_support_filter_all(a)); 244caf54c4fSMartin Matuska assertA(0 == archive_read_open_memory(a, buff, used)); 245caf54c4fSMartin Matuska 246caf54c4fSMartin Matuska /* First item has no ACLs */ 247caf54c4fSMartin Matuska assertA(0 == archive_read_next_header(a, &ae)); 248caf54c4fSMartin Matuska failure("Basic ACLs shouldn't be stored as extended ACLs"); 249caf54c4fSMartin Matuska assert(0 == archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS)); 250caf54c4fSMartin Matuska failure("Basic ACLs should set mode to 0142, not %04o", 251caf54c4fSMartin Matuska archive_entry_mode(ae)&0777); 252caf54c4fSMartin Matuska assert((archive_entry_mode(ae) & 0777) == 0142); 253caf54c4fSMartin Matuska 254caf54c4fSMartin Matuska /* Second item has a few ACLs */ 255caf54c4fSMartin Matuska assertA(0 == archive_read_next_header(a, &ae)); 256caf54c4fSMartin Matuska failure("One extended ACL should flag all ACLs to be returned."); 257caf54c4fSMartin Matuska assert(4 == archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS)); 258caf54c4fSMartin Matuska compare_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]), 0142); 259caf54c4fSMartin Matuska failure("Basic ACLs should set mode to 0142, not %04o", 260caf54c4fSMartin Matuska archive_entry_mode(ae)&0777); 261caf54c4fSMartin Matuska assert((archive_entry_mode(ae) & 0777) == 0142); 262caf54c4fSMartin Matuska 263caf54c4fSMartin Matuska /* Third item has pretty extensive ACLs */ 264caf54c4fSMartin Matuska assertA(0 == archive_read_next_header(a, &ae)); 265caf54c4fSMartin Matuska assertEqualInt(6, archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS)); 266caf54c4fSMartin Matuska compare_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0]), 0543); 267caf54c4fSMartin Matuska failure("Basic ACLs should set mode to 0543, not %04o", 268caf54c4fSMartin Matuska archive_entry_mode(ae)&0777); 269caf54c4fSMartin Matuska assert((archive_entry_mode(ae) & 0777) == 0543); 270caf54c4fSMartin Matuska 271caf54c4fSMartin Matuska /* Fourth item has no ACLs */ 272caf54c4fSMartin Matuska assertA(0 == archive_read_next_header(a, &ae)); 273caf54c4fSMartin Matuska failure("Basic ACLs shouldn't be stored as extended ACLs"); 274caf54c4fSMartin Matuska assert(0 == archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS)); 275caf54c4fSMartin Matuska failure("Basic ACLs should set mode to 0142, not %04o", 276caf54c4fSMartin Matuska archive_entry_mode(ae)&0777); 277caf54c4fSMartin Matuska assert((archive_entry_mode(ae) & 0777) == 0142); 278caf54c4fSMartin Matuska 279caf54c4fSMartin Matuska /* Close the archive. */ 2806c95142eSMartin Matuska assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a)); 2816c95142eSMartin Matuska assertEqualInt(ARCHIVE_OK, archive_read_free(a)); 282caf54c4fSMartin Matuska } 283