1228753Smm/*- 2228753Smm * Copyright (c) 2003-2007 Tim Kientzle 3228753Smm * All rights reserved. 4228753Smm * 5228753Smm * Redistribution and use in source and binary forms, with or without 6228753Smm * modification, are permitted provided that the following conditions 7228753Smm * are met: 8228753Smm * 1. Redistributions of source code must retain the above copyright 9228753Smm * notice, this list of conditions and the following disclaimer. 10228753Smm * 2. Redistributions in binary form must reproduce the above copyright 11228753Smm * notice, this list of conditions and the following disclaimer in the 12228753Smm * documentation and/or other materials provided with the distribution. 13228753Smm * 14228753Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 15228753Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16228753Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17228753Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 18228753Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19228753Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20228753Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21228753Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22228753Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23228753Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24228753Smm */ 25228753Smm#include "test.h" 26228763Smm__FBSDID("$FreeBSD$"); 27228753Smm 28228753Smm/* 29228753Smm * Exercise the system-independent portion of the ACL support. 30228753Smm * Check that pax archive can save and restore ACL data. 31228753Smm * 32228753Smm * This should work on all systems, regardless of whether local 33228753Smm * filesystems support ACLs or not. 34228753Smm */ 35228753Smm 36228753Smmstatic unsigned char buff[16384]; 37228753Smm 38228753Smmstruct acl_t { 39228753Smm int type; /* Type of ACL: "access" or "default" */ 40228753Smm int permset; /* Permissions for this class of users. */ 41228753Smm int tag; /* Owner, User, Owning group, group, other, etc. */ 42228753Smm int qual; /* GID or UID of user/group, depending on tag. */ 43228753Smm const char *name; /* Name of user/group, depending on tag. */ 44228753Smm}; 45228753Smm 46228753Smmstatic struct acl_t acls0[] = { 47228753Smm { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_EXECUTE, 48228753Smm ARCHIVE_ENTRY_ACL_USER_OBJ, 0, "" }, 49228753Smm { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_READ, 50228753Smm ARCHIVE_ENTRY_ACL_GROUP_OBJ, 0, "" }, 51228753Smm { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_WRITE, 52228753Smm ARCHIVE_ENTRY_ACL_OTHER, 0, "" }, 53228753Smm}; 54228753Smm 55228753Smmstatic struct acl_t acls1[] = { 56228753Smm { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_EXECUTE, 57228753Smm ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" }, 58228753Smm { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_READ, 59228753Smm ARCHIVE_ENTRY_ACL_USER, 77, "user77" }, 60228753Smm { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_READ, 61228753Smm ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" }, 62228753Smm { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_WRITE, 63228753Smm ARCHIVE_ENTRY_ACL_OTHER, -1, "" }, 64228753Smm}; 65228753Smm 66228753Smmstatic struct acl_t acls2[] = { 67228753Smm { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_EXECUTE | ARCHIVE_ENTRY_ACL_READ, 68228753Smm ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" }, 69228753Smm { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_READ, 70228753Smm ARCHIVE_ENTRY_ACL_USER, 77, "user77" }, 71228753Smm { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 0, 72228753Smm ARCHIVE_ENTRY_ACL_USER, 78, "user78" }, 73228753Smm { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_READ, 74228753Smm ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" }, 75228753Smm { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 0007, 76228753Smm ARCHIVE_ENTRY_ACL_GROUP, 78, "group78" }, 77228753Smm { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_WRITE | ARCHIVE_ENTRY_ACL_EXECUTE, 78228753Smm ARCHIVE_ENTRY_ACL_OTHER, -1, "" }, 79228753Smm}; 80228753Smm 81228753Smmstatic void 82228753Smmset_acls(struct archive_entry *ae, struct acl_t *acls, int n) 83228753Smm{ 84228753Smm int i; 85228753Smm 86228753Smm archive_entry_acl_clear(ae); 87228753Smm for (i = 0; i < n; i++) { 88228753Smm archive_entry_acl_add_entry(ae, 89228753Smm acls[i].type, acls[i].permset, acls[i].tag, acls[i].qual, 90228753Smm acls[i].name); 91228753Smm } 92228753Smm} 93228753Smm 94228753Smmstatic int 95228753Smmacl_match(struct acl_t *acl, int type, int permset, int tag, int qual, const char *name) 96228753Smm{ 97228753Smm if (type != acl->type) 98228753Smm return (0); 99228753Smm if (permset != acl->permset) 100228753Smm return (0); 101228753Smm if (tag != acl->tag) 102228753Smm return (0); 103228753Smm if (tag == ARCHIVE_ENTRY_ACL_USER_OBJ) 104228753Smm return (1); 105228753Smm if (tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ) 106228753Smm return (1); 107228753Smm if (tag == ARCHIVE_ENTRY_ACL_OTHER) 108228753Smm return (1); 109228753Smm if (qual != acl->qual) 110228753Smm return (0); 111228753Smm if (name == NULL) 112228753Smm return (acl->name == NULL || acl->name[0] == '\0'); 113228753Smm if (acl->name == NULL) 114228753Smm return (name == NULL || name[0] == '\0'); 115228753Smm return (0 == strcmp(name, acl->name)); 116228753Smm} 117228753Smm 118228753Smmstatic void 119228753Smmcompare_acls(struct archive_entry *ae, struct acl_t *acls, int n, int mode) 120228753Smm{ 121228753Smm int *marker = malloc(sizeof(marker[0]) * n); 122228753Smm int i; 123228753Smm int r; 124228753Smm int type, permset, tag, qual; 125228753Smm int matched; 126228753Smm const char *name; 127228753Smm 128228753Smm for (i = 0; i < n; i++) 129228753Smm marker[i] = i; 130228753Smm 131228753Smm while (0 == (r = archive_entry_acl_next(ae, 132228753Smm ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 133228753Smm &type, &permset, &tag, &qual, &name))) { 134228753Smm for (i = 0, matched = 0; i < n && !matched; i++) { 135228753Smm if (acl_match(&acls[marker[i]], type, permset, 136228753Smm tag, qual, name)) { 137228753Smm /* We found a match; remove it. */ 138228753Smm marker[i] = marker[n - 1]; 139228753Smm n--; 140228753Smm matched = 1; 141228753Smm } 142228753Smm } 143228753Smm if (tag == ARCHIVE_ENTRY_ACL_USER_OBJ) { 144228753Smm if (!matched) printf("No match for user_obj perm\n"); 145228753Smm failure("USER_OBJ permset (%02o) != user mode (%02o)", 146228753Smm permset, 07 & (mode >> 6)); 147228753Smm assert((permset << 6) == (mode & 0700)); 148228753Smm } else if (tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ) { 149228753Smm if (!matched) printf("No match for group_obj perm\n"); 150228753Smm failure("GROUP_OBJ permset %02o != group mode %02o", 151228753Smm permset, 07 & (mode >> 3)); 152228753Smm assert((permset << 3) == (mode & 0070)); 153228753Smm } else if (tag == ARCHIVE_ENTRY_ACL_OTHER) { 154228753Smm if (!matched) printf("No match for other perm\n"); 155228753Smm failure("OTHER permset (%02o) != other mode (%02o)", 156228753Smm permset, mode & 07); 157228753Smm assert((permset << 0) == (mode & 0007)); 158228753Smm } else { 159228753Smm failure("Could not find match for ACL " 160228753Smm "(type=%d,permset=%d,tag=%d,qual=%d,name=``%s'')", 161228753Smm type, permset, tag, qual, name); 162228753Smm assert(matched == 1); 163228753Smm } 164228753Smm } 165228753Smm assertEqualInt(ARCHIVE_EOF, r); 166232153Smm assert((mode_t)(mode & 0777) == (archive_entry_mode(ae) & 0777)); 167228753Smm failure("Could not find match for ACL " 168228753Smm "(type=%d,permset=%d,tag=%d,qual=%d,name=``%s'')", 169228753Smm acls[marker[0]].type, acls[marker[0]].permset, 170228753Smm acls[marker[0]].tag, acls[marker[0]].qual, acls[marker[0]].name); 171228753Smm assert(n == 0); /* Number of ACLs not matched should == 0 */ 172228753Smm free(marker); 173228753Smm} 174228753Smm 175228753SmmDEFINE_TEST(test_acl_pax) 176228753Smm{ 177228753Smm struct archive *a; 178228753Smm struct archive_entry *ae; 179228753Smm size_t used; 180228753Smm FILE *f; 181232153Smm void *reference; 182232153Smm size_t reference_size; 183228753Smm 184228753Smm /* Write an archive to memory. */ 185228753Smm assert(NULL != (a = archive_write_new())); 186228753Smm assertA(0 == archive_write_set_format_pax(a)); 187248616Smm assertA(0 == archive_write_add_filter_none(a)); 188228753Smm assertA(0 == archive_write_set_bytes_per_block(a, 1)); 189228753Smm assertA(0 == archive_write_set_bytes_in_last_block(a, 1)); 190228753Smm assertA(0 == archive_write_open_memory(a, buff, sizeof(buff), &used)); 191228753Smm 192228753Smm /* Write a series of files to the archive with different ACL info. */ 193228753Smm 194228753Smm /* Create a simple archive_entry. */ 195228753Smm assert((ae = archive_entry_new()) != NULL); 196228753Smm archive_entry_set_pathname(ae, "file"); 197228753Smm archive_entry_set_mode(ae, S_IFREG | 0777); 198228753Smm 199228753Smm /* Basic owner/owning group should just update mode bits. */ 200228753Smm set_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0])); 201228753Smm assertA(0 == archive_write_header(a, ae)); 202228753Smm 203228753Smm /* With any extended ACL entry, we should read back a full set. */ 204228753Smm set_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0])); 205228753Smm assertA(0 == archive_write_header(a, ae)); 206228753Smm 207228753Smm 208228753Smm /* A more extensive set of ACLs. */ 209228753Smm set_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0])); 210228753Smm assertA(0 == archive_write_header(a, ae)); 211228753Smm 212228753Smm /* 213228753Smm * Check that clearing ACLs gets rid of them all by repeating 214228753Smm * the first test. 215228753Smm */ 216228753Smm set_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0])); 217228753Smm assertA(0 == archive_write_header(a, ae)); 218228753Smm archive_entry_free(ae); 219228753Smm 220228753Smm /* Close out the archive. */ 221232153Smm assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a)); 222232153Smm assertEqualInt(ARCHIVE_OK, archive_write_free(a)); 223228753Smm 224228753Smm /* Write out the data we generated to a file for manual inspection. */ 225228753Smm assert(NULL != (f = fopen("testout", "wb"))); 226228753Smm assertEqualInt(used, (size_t)fwrite(buff, 1, (unsigned int)used, f)); 227228753Smm fclose(f); 228228753Smm 229228753Smm /* Write out the reference data to a file for manual inspection. */ 230232153Smm extract_reference_file("test_acl_pax.tar"); 231232153Smm reference = slurpfile(&reference_size, "test_acl_pax.tar"); 232228753Smm 233228753Smm /* Assert that the generated data matches the built-in reference data.*/ 234232153Smm failure("Generated pax archive does not match reference; compare 'testout' to 'test_acl_pax.tar' reference file."); 235232153Smm assertEqualMem(buff, reference, reference_size); 236232153Smm failure("Generated pax archive does not match reference; compare 'testout' to 'test_acl_pax.tar' reference file."); 237232153Smm assertEqualInt((int)used, reference_size); 238232153Smm free(reference); 239228753Smm 240228753Smm /* Read back each entry and check that the ACL data is right. */ 241228753Smm assert(NULL != (a = archive_read_new())); 242228753Smm assertA(0 == archive_read_support_format_all(a)); 243232153Smm assertA(0 == archive_read_support_filter_all(a)); 244228753Smm assertA(0 == archive_read_open_memory(a, buff, used)); 245228753Smm 246228753Smm /* First item has no ACLs */ 247228753Smm assertA(0 == archive_read_next_header(a, &ae)); 248228753Smm failure("Basic ACLs shouldn't be stored as extended ACLs"); 249228753Smm assert(0 == archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS)); 250228753Smm failure("Basic ACLs should set mode to 0142, not %04o", 251228753Smm archive_entry_mode(ae)&0777); 252228753Smm assert((archive_entry_mode(ae) & 0777) == 0142); 253228753Smm 254228753Smm /* Second item has a few ACLs */ 255228753Smm assertA(0 == archive_read_next_header(a, &ae)); 256228753Smm failure("One extended ACL should flag all ACLs to be returned."); 257228753Smm assert(4 == archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS)); 258228753Smm compare_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]), 0142); 259228753Smm failure("Basic ACLs should set mode to 0142, not %04o", 260228753Smm archive_entry_mode(ae)&0777); 261228753Smm assert((archive_entry_mode(ae) & 0777) == 0142); 262228753Smm 263228753Smm /* Third item has pretty extensive ACLs */ 264228753Smm assertA(0 == archive_read_next_header(a, &ae)); 265228753Smm assertEqualInt(6, archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS)); 266228753Smm compare_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0]), 0543); 267228753Smm failure("Basic ACLs should set mode to 0543, not %04o", 268228753Smm archive_entry_mode(ae)&0777); 269228753Smm assert((archive_entry_mode(ae) & 0777) == 0543); 270228753Smm 271228753Smm /* Fourth item has no ACLs */ 272228753Smm assertA(0 == archive_read_next_header(a, &ae)); 273228753Smm failure("Basic ACLs shouldn't be stored as extended ACLs"); 274228753Smm assert(0 == archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS)); 275228753Smm failure("Basic ACLs should set mode to 0142, not %04o", 276228753Smm archive_entry_mode(ae)&0777); 277228753Smm assert((archive_entry_mode(ae) & 0777) == 0142); 278228753Smm 279228753Smm /* Close the archive. */ 280232153Smm assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a)); 281232153Smm assertEqualInt(ARCHIVE_OK, archive_read_free(a)); 282228753Smm} 283