1231200Smm/*- 2231200Smm * Copyright (c) 2003-2010 Tim Kientzle 3231200Smm * All rights reserved. 4231200Smm * 5231200Smm * Redistribution and use in source and binary forms, with or without 6231200Smm * modification, are permitted provided that the following conditions 7231200Smm * are met: 8231200Smm * 1. Redistributions of source code must retain the above copyright 9231200Smm * notice, this list of conditions and the following disclaimer. 10231200Smm * 2. Redistributions in binary form must reproduce the above copyright 11231200Smm * notice, this list of conditions and the following disclaimer in the 12231200Smm * documentation and/or other materials provided with the distribution. 13231200Smm * 14231200Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 15231200Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16231200Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17231200Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 18231200Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19231200Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20231200Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21231200Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22231200Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23231200Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24231200Smm */ 25231200Smm#include "test.h" 26231200Smm__FBSDID("$FreeBSD$"); 27231200Smm 28231200Smm/* 29231200Smm * Exercise the system-independent portion of the ACL support. 30231200Smm * Check that archive_entry objects can save and restore NFS4 ACL data. 31231200Smm * 32231200Smm * This should work on all systems, regardless of whether local 33231200Smm * filesystems support ACLs or not. 34231200Smm */ 35231200Smm 36231200Smmstruct acl_t { 37231200Smm int type; /* Type of entry: "allow" or "deny" */ 38231200Smm int permset; /* Permissions for this class of users. */ 39231200Smm int tag; /* Owner, User, Owning group, group, everyone, etc. */ 40231200Smm int qual; /* GID or UID of user/group, depending on tag. */ 41231200Smm const char *name; /* Name of user/group, depending on tag. */ 42231200Smm}; 43231200Smm 44231200Smmstatic struct acl_t acls1[] = { 45231200Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE, 46231200Smm ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" }, 47231200Smm { ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_READ_DATA, 48231200Smm ARCHIVE_ENTRY_ACL_USER, 77, "user77" }, 49231200Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_DATA, 50231200Smm ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" }, 51231200Smm { ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_WRITE_DATA, 52231200Smm ARCHIVE_ENTRY_ACL_EVERYONE, -1, "" }, 53231200Smm}; 54231200Smm 55231200Smmstatic struct acl_t acls2[] = { 56231200Smm /* An entry for each type. */ 57231200Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, 0, 58231200Smm ARCHIVE_ENTRY_ACL_USER, 108, "user108" }, 59231200Smm { ARCHIVE_ENTRY_ACL_TYPE_DENY, 0, 60231200Smm ARCHIVE_ENTRY_ACL_USER, 109, "user109" }, 61231200Smm { ARCHIVE_ENTRY_ACL_TYPE_AUDIT, 0, 62231200Smm ARCHIVE_ENTRY_ACL_USER, 110, "user110" }, 63231200Smm { ARCHIVE_ENTRY_ACL_TYPE_ALARM, 0, 64231200Smm ARCHIVE_ENTRY_ACL_USER, 111, "user111" }, 65231200Smm 66231200Smm /* An entry for each permission. */ 67231200Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE, 68231200Smm ARCHIVE_ENTRY_ACL_USER, 112, "user112" }, 69231200Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_DATA, 70231200Smm ARCHIVE_ENTRY_ACL_USER, 113, "user113" }, 71231200Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, 72231200Smm ARCHIVE_ENTRY_ACL_USER, 114, "user114" }, 73231200Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_DATA, 74231200Smm ARCHIVE_ENTRY_ACL_USER, 115, "user115" }, 75231200Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_ADD_FILE, 76231200Smm ARCHIVE_ENTRY_ACL_USER, 116, "user116" }, 77231200Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_APPEND_DATA, 78231200Smm ARCHIVE_ENTRY_ACL_USER, 117, "user117" }, 79231200Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, 80231200Smm ARCHIVE_ENTRY_ACL_USER, 118, "user118" }, 81231200Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, 82231200Smm ARCHIVE_ENTRY_ACL_USER, 119, "user119" }, 83231200Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, 84231200Smm ARCHIVE_ENTRY_ACL_USER, 120, "user120" }, 85231200Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_DELETE_CHILD, 86231200Smm ARCHIVE_ENTRY_ACL_USER, 121, "user121" }, 87231200Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, 88231200Smm ARCHIVE_ENTRY_ACL_USER, 122, "user122" }, 89231200Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, 90231200Smm ARCHIVE_ENTRY_ACL_USER, 123, "user123" }, 91231200Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_DELETE, 92231200Smm ARCHIVE_ENTRY_ACL_USER, 124, "user124" }, 93231200Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_ACL, 94231200Smm ARCHIVE_ENTRY_ACL_USER, 125, "user125" }, 95231200Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_ACL, 96231200Smm ARCHIVE_ENTRY_ACL_USER, 126, "user126" }, 97231200Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_OWNER, 98231200Smm ARCHIVE_ENTRY_ACL_USER, 127, "user127" }, 99231200Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_SYNCHRONIZE, 100231200Smm ARCHIVE_ENTRY_ACL_USER, 128, "user128" }, 101231200Smm 102231200Smm /* One entry with each inheritance value. */ 103231200Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, 104231200Smm ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, 105231200Smm ARCHIVE_ENTRY_ACL_USER, 129, "user129" }, 106231200Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, 107231200Smm ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, 108231200Smm ARCHIVE_ENTRY_ACL_USER, 130, "user130" }, 109231200Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, 110231200Smm ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, 111231200Smm ARCHIVE_ENTRY_ACL_USER, 131, "user131" }, 112231200Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, 113231200Smm ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, 114231200Smm ARCHIVE_ENTRY_ACL_USER, 132, "user132" }, 115231200Smm { ARCHIVE_ENTRY_ACL_TYPE_AUDIT, 116231200Smm ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, 117231200Smm ARCHIVE_ENTRY_ACL_USER, 133, "user133" }, 118231200Smm { ARCHIVE_ENTRY_ACL_TYPE_AUDIT, 119231200Smm ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, 120231200Smm ARCHIVE_ENTRY_ACL_USER, 134, "user134" }, 121231200Smm 122231200Smm /* One entry for each qualifier. */ 123231200Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE, 124231200Smm ARCHIVE_ENTRY_ACL_USER, 135, "user135" }, 125231200Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE, 126231200Smm ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" }, 127231200Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE, 128231200Smm ARCHIVE_ENTRY_ACL_GROUP, 136, "group136" }, 129231200Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE, 130231200Smm ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" }, 131231200Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE, 132231200Smm ARCHIVE_ENTRY_ACL_EVERYONE, -1, "" }, 133231200Smm}; 134231200Smm 135231200Smm/* 136231200Smm * Entries that should be rejected when we attempt to set them 137231200Smm * on an ACL that already has NFS4 entries. 138231200Smm */ 139231200Smmstatic struct acl_t acls_bad[] = { 140231200Smm /* POSIX.1e ACL types */ 141231200Smm { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_EXECUTE, 142231200Smm ARCHIVE_ENTRY_ACL_USER, 78, "" }, 143231200Smm { ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, ARCHIVE_ENTRY_ACL_EXECUTE, 144231200Smm ARCHIVE_ENTRY_ACL_USER, 78, "" }, 145231200Smm 146231200Smm /* POSIX.1e tags */ 147231200Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE, 148231200Smm ARCHIVE_ENTRY_ACL_OTHER, -1, "" }, 149231200Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE, 150231200Smm ARCHIVE_ENTRY_ACL_MASK, -1, "" }, 151231200Smm 152231200Smm /* POSIX.1e permissions */ 153231200Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ, 154231200Smm ARCHIVE_ENTRY_ACL_EVERYONE, -1, "" }, 155231200Smm { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE, 156231200Smm ARCHIVE_ENTRY_ACL_EVERYONE, -1, "" }, 157231200Smm}; 158231200Smm 159231200Smmstatic void 160231200Smmset_acls(struct archive_entry *ae, struct acl_t *acls, int n) 161231200Smm{ 162231200Smm int i; 163231200Smm 164231200Smm archive_entry_acl_clear(ae); 165231200Smm for (i = 0; i < n; i++) { 166231200Smm failure("type=%d, permset=%d, tag=%d, qual=%d name=%s", 167231200Smm acls[i].type, acls[i].permset, acls[i].tag, 168231200Smm acls[i].qual, acls[i].name); 169231200Smm assertEqualInt(ARCHIVE_OK, 170231200Smm archive_entry_acl_add_entry(ae, 171231200Smm acls[i].type, acls[i].permset, acls[i].tag, 172231200Smm acls[i].qual, acls[i].name)); 173231200Smm } 174231200Smm} 175231200Smm 176231200Smmstatic int 177248616Smmacl_match(struct acl_t *acl, int type, int permset, int tag, int qual, 178248616Smm const char *name) 179231200Smm{ 180248616Smm if (acl == NULL) 181248616Smm return (0); 182231200Smm if (type != acl->type) 183231200Smm return (0); 184231200Smm if (permset != acl->permset) 185231200Smm return (0); 186231200Smm if (tag != acl->tag) 187231200Smm return (0); 188231200Smm if (tag == ARCHIVE_ENTRY_ACL_USER_OBJ) 189231200Smm return (1); 190231200Smm if (tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ) 191231200Smm return (1); 192231200Smm if (tag == ARCHIVE_ENTRY_ACL_EVERYONE) 193231200Smm return (1); 194231200Smm if (qual != acl->qual) 195231200Smm return (0); 196231200Smm if (name == NULL) { 197231200Smm if (acl->name == NULL || acl->name[0] == '\0') 198231200Smm return (1); 199248616Smm return (0); 200231200Smm } 201231200Smm if (acl->name == NULL) { 202231200Smm if (name[0] == '\0') 203231200Smm return (1); 204248616Smm return (0); 205231200Smm } 206231200Smm return (0 == strcmp(name, acl->name)); 207231200Smm} 208231200Smm 209231200Smmstatic void 210231200Smmcompare_acls(struct archive_entry *ae, struct acl_t *acls, int n) 211231200Smm{ 212231200Smm int *marker = malloc(sizeof(marker[0]) * n); 213231200Smm int i; 214231200Smm int r; 215231200Smm int type, permset, tag, qual; 216231200Smm int matched; 217231200Smm const char *name; 218231200Smm 219231200Smm for (i = 0; i < n; i++) 220231200Smm marker[i] = i; 221231200Smm 222231200Smm while (0 == (r = archive_entry_acl_next(ae, 223231200Smm ARCHIVE_ENTRY_ACL_TYPE_NFS4, 224231200Smm &type, &permset, &tag, &qual, &name))) { 225231200Smm for (i = 0, matched = 0; i < n && !matched; i++) { 226231200Smm if (acl_match(&acls[marker[i]], type, permset, 227231200Smm tag, qual, name)) { 228231200Smm /* We found a match; remove it. */ 229231200Smm marker[i] = marker[n - 1]; 230231200Smm n--; 231231200Smm matched = 1; 232231200Smm } 233231200Smm } 234231200Smm failure("Could not find match for ACL " 235231200Smm "(type=%d,permset=%d,tag=%d,qual=%d,name=``%s'')", 236231200Smm type, permset, tag, qual, name); 237231200Smm assertEqualInt(1, matched); 238231200Smm } 239231200Smm assertEqualInt(ARCHIVE_EOF, r); 240231200Smm failure("Could not find match for ACL " 241231200Smm "(type=%d,permset=%d,tag=%d,qual=%d,name=``%s'')", 242231200Smm acls[marker[0]].type, acls[marker[0]].permset, 243231200Smm acls[marker[0]].tag, acls[marker[0]].qual, acls[marker[0]].name); 244231200Smm assertEqualInt(0, n); /* Number of ACLs not matched should == 0 */ 245231200Smm free(marker); 246231200Smm} 247231200Smm 248231200SmmDEFINE_TEST(test_acl_nfs4) 249231200Smm{ 250231200Smm struct archive_entry *ae; 251231200Smm int i; 252231200Smm 253231200Smm /* Create a simple archive_entry. */ 254231200Smm assert((ae = archive_entry_new()) != NULL); 255231200Smm archive_entry_set_pathname(ae, "file"); 256231200Smm archive_entry_set_mode(ae, S_IFREG | 0777); 257231200Smm 258231200Smm /* Store and read back some basic ACL entries. */ 259231200Smm set_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0])); 260231200Smm assertEqualInt(4, 261231200Smm archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_NFS4)); 262231200Smm compare_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0])); 263231200Smm 264231200Smm /* A more extensive set of ACLs. */ 265231200Smm set_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0])); 266231200Smm assertEqualInt(32, 267231200Smm archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_NFS4)); 268231200Smm compare_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0])); 269231200Smm 270231200Smm /* 271231200Smm * Check that clearing ACLs gets rid of them all by repeating 272231200Smm * the first test. 273231200Smm */ 274231200Smm set_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0])); 275231200Smm failure("Basic ACLs shouldn't be stored as extended ACLs"); 276231200Smm assertEqualInt(4, 277231200Smm archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_NFS4)); 278231200Smm 279231200Smm /* 280231200Smm * Different types of malformed ACL entries that should 281231200Smm * fail when added to existing NFS4 ACLs. 282231200Smm */ 283231200Smm set_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0])); 284232153Smm for (i = 0; i < (int)(sizeof(acls_bad)/sizeof(acls_bad[0])); ++i) { 285231200Smm struct acl_t *p = &acls_bad[i]; 286231200Smm failure("Malformed ACL test #%d", i); 287231200Smm assertEqualInt(ARCHIVE_FAILED, 288231200Smm archive_entry_acl_add_entry(ae, 289231200Smm p->type, p->permset, p->tag, p->qual, p->name)); 290231200Smm failure("Malformed ACL test #%d", i); 291231200Smm assertEqualInt(32, 292231200Smm archive_entry_acl_reset(ae, 293231200Smm ARCHIVE_ENTRY_ACL_TYPE_NFS4)); 294231200Smm } 295231200Smm archive_entry_free(ae); 296231200Smm} 297