freebsd-skq/lib/libarchive/test/test_acl_basic.c
Tim Kientzle d4c6c416dc New tests for system-independent ACL support.
These tests verify that archive_entry objects can store and return
ACL data and that pax format archives can read and write ACL
information.  These do not (yet) test that ACL data is read or
written to disk correctly.  (And hence would not have caught the
recent snafu about ACL read-from-disk being turned off.)
2007-03-08 06:09:27 +00:00

228 lines
7.9 KiB
C

/*-
* Copyright (c) 2003-2007 Tim Kientzle
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test.h"
__FBSDID("$FreeBSD$");
/*
* Exercise the system-independent portion of the ACL support.
* Check that archive_entry objects can save and restore ACL data
* and that pax archive can save and restore ACL data.
*
* This should work on all systems, regardless of whether local
* filesystems support ACLs or not.
*/
static unsigned char buff[16384];
struct acl_t {
int type; /* Type of ACL: "access" or "default" */
int permset; /* Permissions for this class of users. */
int tag; /* Owner, User, Owning group, group, other, etc. */
int qual; /* GID or UID of user/group, depending on tag. */
char *name; /* Name of user/group, depending on tag. */
};
struct acl_t acls0[] = {
{ ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_EXECUTE,
ARCHIVE_ENTRY_ACL_USER_OBJ, 0, "" },
{ ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_READ,
ARCHIVE_ENTRY_ACL_GROUP_OBJ, 0, "" },
{ ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_WRITE,
ARCHIVE_ENTRY_ACL_OTHER, 0, "" },
};
struct acl_t acls1[] = {
{ ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_EXECUTE,
ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" },
{ ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_READ,
ARCHIVE_ENTRY_ACL_USER, 77, "user77" },
{ ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_READ,
ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" },
{ ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_WRITE,
ARCHIVE_ENTRY_ACL_OTHER, -1, "" },
};
struct acl_t acls2[] = {
{ ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_EXECUTE | ARCHIVE_ENTRY_ACL_READ,
ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" },
{ ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_READ,
ARCHIVE_ENTRY_ACL_USER, 77, "user77" },
{ ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 0,
ARCHIVE_ENTRY_ACL_USER, 78, "user78" },
{ ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_READ,
ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" },
{ ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 0007,
ARCHIVE_ENTRY_ACL_GROUP, 78, "group78" },
{ ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_WRITE | ARCHIVE_ENTRY_ACL_EXECUTE,
ARCHIVE_ENTRY_ACL_OTHER, -1, "" },
};
void
set_acls(struct archive_entry *ae, struct acl_t *acls, int n)
{
int i;
archive_entry_acl_clear(ae);
for (i = 0; i < n; i++) {
archive_entry_acl_add_entry(ae,
acls[i].type, acls[i].permset, acls[i].tag, acls[i].qual,
acls[i].name);
}
}
int
acl_match(struct acl_t *acl, int type, int permset, int tag, int qual, const char *name)
{
if (type != acl->type)
return (0);
if (permset != acl->permset)
return (0);
if (tag != acl->tag)
return (0);
if (tag == ARCHIVE_ENTRY_ACL_USER_OBJ)
return (1);
if (tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ)
return (1);
if (tag == ARCHIVE_ENTRY_ACL_OTHER)
return (1);
if (qual != acl->qual)
return (0);
if (name == NULL) {
if (acl->name == NULL || acl->name[0] == '\0')
return (1);
}
if (acl->name == NULL) {
if (name[0] == '\0')
return (1);
}
return (0 == strcmp(name, acl->name));
}
void
compare_acls(struct archive_entry *ae, struct acl_t *acls, int n, int mode)
{
int *marker = malloc(sizeof(marker[0]) * n);
int marker_i, i;
int r;
int type, permset, tag, qual;
int matched;
const char *name;
for (i = 0; i < n; i++)
marker[i] = i;
while (0 == (r = archive_entry_acl_next(ae,
ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
&type, &permset, &tag, &qual, &name))) {
for (i = 0, matched = 0; i < n && !matched; i++) {
if (acl_match(&acls[marker[i]], type, permset,
tag, qual, name)) {
/* We found a match; remove it. */
marker[i] = marker[n - 1];
n--;
matched = 1;
}
}
if (tag == ARCHIVE_ENTRY_ACL_USER_OBJ) {
if (!matched) printf("No match for user_obj perm\n");
failure("USER_OBJ permset (%02o) != user mode (%02o)",
permset, 07 & (mode >> 6));
assert((permset << 6) == (mode & 0700));
} else if (tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ) {
if (!matched) printf("No match for group_obj perm\n");
failure("GROUP_OBJ permset %02o != group mode %02o",
permset, 07 & (mode >> 3));
assert((permset << 3) == (mode & 0070));
} else if (tag == ARCHIVE_ENTRY_ACL_OTHER) {
if (!matched) printf("No match for other perm\n");
failure("OTHER permset (%02o) != other mode (%02o)",
permset, mode & 07);
assert((permset << 0) == (mode & 0007));
} else {
failure("Could not find match for ACL "
"(type=%d,permset=%d,tag=%d,qual=%d,name=``%s'')",
type, permset, tag, qual, name);
assert(matched == 1);
}
}
assertEqualInt(ARCHIVE_EOF, r);
assert((mode & 0777) == (archive_entry_mode(ae) & 0777));
failure("Could not find match for ACL "
"(type=%d,permset=%d,tag=%d,qual=%d,name=``%s'')",
acls[marker[0]].type, acls[marker[0]].permset,
acls[marker[0]].tag, acls[marker[0]].qual, acls[marker[0]].name);
assert(n == 0); /* Number of ACLs not matched should == 0 */
}
DEFINE_TEST(test_acl_basic)
{
int i;
struct archive *a;
struct archive_entry *ae;
/* Create a simple archive_entry. */
assert((ae = archive_entry_new()) != NULL);
archive_entry_set_pathname(ae, "file");
archive_entry_set_mode(ae, S_IFREG | 0777);
/* Basic owner/owning group should just update mode bits. */
set_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]));
failure("Basic ACLs shouldn't be stored as extended ACLs");
assert(0 == archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
failure("Basic ACLs should set mode to 0142, not %04o",
archive_entry_mode(ae)&0777);
assert((archive_entry_mode(ae) & 0777) == 0142);
/* With any extended ACL entry, we should read back a full set. */
set_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]));
failure("One extended ACL should flag all ACLs to be returned.");
assert(4 == archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
compare_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]), 0142);
failure("Basic ACLs should set mode to 0142, not %04o",
archive_entry_mode(ae)&0777);
assert((archive_entry_mode(ae) & 0777) == 0142);
/* A more extensive set of ACLs. */
set_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0]));
assertEqualInt(6, archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
compare_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0]), 0543);
failure("Basic ACLs should set mode to 0543, not %04o",
archive_entry_mode(ae)&0777);
assert((archive_entry_mode(ae) & 0777) == 0543);
/*
* Check that clearing ACLs gets rid of them all by repeating
* the first test.
*/
set_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]));
failure("Basic ACLs shouldn't be stored as extended ACLs");
assert(0 == archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
failure("Basic ACLs should set mode to 0142, not %04o",
archive_entry_mode(ae)&0777);
assert((archive_entry_mode(ae) & 0777) == 0142);
}