xref: /NextBSD/contrib/libarchive/libarchive/test/test_acl_freebsd_nfs4.c (revision eb1a5f8de9f7ea602c373a710f531abbf81141c4)
1 /*-
2  * Copyright (c) 2003-2010 Tim Kientzle
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 #include "test.h"
26 __FBSDID("$FreeBSD$");
27 
28 #if defined(__FreeBSD__) && __FreeBSD__ >= 8
29 #define _ACL_PRIVATE
30 #include <sys/acl.h>
31 
32 struct myacl_t {
33 	int type;
34 	int permset;
35 	int tag;
36 	int qual; /* GID or UID of user/group, depending on tag. */
37 	const char *name; /* Name of user/group, depending on tag. */
38 };
39 
40 static struct myacl_t acls_reg[] = {
41 	/* For this test, we need the file owner to be able to read and write the ACL. */
42 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
43 	  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,
44 	  ARCHIVE_ENTRY_ACL_USER_OBJ, -1, ""},
45 
46 	/* An entry for each type. */
47 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE,
48 	  ARCHIVE_ENTRY_ACL_USER, 108, "user108" },
49 	{ ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_EXECUTE,
50 	  ARCHIVE_ENTRY_ACL_USER, 109, "user109" },
51 
52 	/* An entry for each permission. */
53 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE,
54 	  ARCHIVE_ENTRY_ACL_USER, 112, "user112" },
55 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_DATA,
56 	  ARCHIVE_ENTRY_ACL_USER, 113, "user113" },
57 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_DATA,
58 	  ARCHIVE_ENTRY_ACL_USER, 115, "user115" },
59 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_APPEND_DATA,
60 	  ARCHIVE_ENTRY_ACL_USER, 117, "user117" },
61 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS,
62 	  ARCHIVE_ENTRY_ACL_USER, 119, "user119" },
63 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS,
64 	  ARCHIVE_ENTRY_ACL_USER, 120, "user120" },
65 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES,
66 	  ARCHIVE_ENTRY_ACL_USER, 122, "user122" },
67 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES,
68 	  ARCHIVE_ENTRY_ACL_USER, 123, "user123" },
69 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_DELETE,
70 	  ARCHIVE_ENTRY_ACL_USER, 124, "user124" },
71 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_ACL,
72 	  ARCHIVE_ENTRY_ACL_USER, 125, "user125" },
73 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_ACL,
74 	  ARCHIVE_ENTRY_ACL_USER, 126, "user126" },
75 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_OWNER,
76 	  ARCHIVE_ENTRY_ACL_USER, 127, "user127" },
77 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_SYNCHRONIZE,
78 	  ARCHIVE_ENTRY_ACL_USER, 128, "user128" },
79 
80 	/* One entry for each qualifier. */
81 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE,
82 	  ARCHIVE_ENTRY_ACL_USER, 135, "user135" },
83 //	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE,
84 //	  ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" },
85 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE,
86 	  ARCHIVE_ENTRY_ACL_GROUP, 136, "group136" },
87 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE,
88 	  ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" },
89 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE,
90 	  ARCHIVE_ENTRY_ACL_EVERYONE, -1, "" }
91 };
92 
93 
94 static struct myacl_t acls_dir[] = {
95 	/* For this test, we need to be able to read and write the ACL. */
96 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_ACL,
97 	  ARCHIVE_ENTRY_ACL_USER_OBJ, -1, ""},
98 
99 	/* An entry for each type. */
100 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY,
101 	  ARCHIVE_ENTRY_ACL_USER, 101, "user101" },
102 	{ ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY,
103 	  ARCHIVE_ENTRY_ACL_USER, 102, "user102" },
104 
105 	/* An entry for each permission. */
106 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY,
107 	  ARCHIVE_ENTRY_ACL_USER, 201, "user201" },
108 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_ADD_FILE,
109 	  ARCHIVE_ENTRY_ACL_USER, 202, "user202" },
110 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY,
111 	  ARCHIVE_ENTRY_ACL_USER, 203, "user203" },
112 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS,
113 	  ARCHIVE_ENTRY_ACL_USER, 204, "user204" },
114 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS,
115 	  ARCHIVE_ENTRY_ACL_USER, 205, "user205" },
116 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_DELETE_CHILD,
117 	  ARCHIVE_ENTRY_ACL_USER, 206, "user206" },
118 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES,
119 	  ARCHIVE_ENTRY_ACL_USER, 207, "user207" },
120 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES,
121 	  ARCHIVE_ENTRY_ACL_USER, 208, "user208" },
122 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_DELETE,
123 	  ARCHIVE_ENTRY_ACL_USER, 209, "user209" },
124 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_ACL,
125 	  ARCHIVE_ENTRY_ACL_USER, 210, "user210" },
126 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_ACL,
127 	  ARCHIVE_ENTRY_ACL_USER, 211, "user211" },
128 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_OWNER,
129 	  ARCHIVE_ENTRY_ACL_USER, 212, "user212" },
130 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_SYNCHRONIZE,
131 	  ARCHIVE_ENTRY_ACL_USER, 213, "user213" },
132 
133 	/* One entry with each inheritance value. */
134 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
135 	  ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT,
136 	  ARCHIVE_ENTRY_ACL_USER, 301, "user301" },
137 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
138 	  ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT,
139 	  ARCHIVE_ENTRY_ACL_USER, 302, "user302" },
140 #if 0
141 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
142 	  ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT,
143 	  ARCHIVE_ENTRY_ACL_USER, 303, "user303" },
144 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
145 	  ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY,
146 	  ARCHIVE_ENTRY_ACL_USER, 304, "user304" },
147 #endif
148 
149 #if 0
150 	/* FreeBSD does not support audit entries. */
151 	{ ARCHIVE_ENTRY_ACL_TYPE_AUDIT,
152 	  ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS,
153 	  ARCHIVE_ENTRY_ACL_USER, 401, "user401" },
154 	{ ARCHIVE_ENTRY_ACL_TYPE_AUDIT,
155 	  ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS,
156 	  ARCHIVE_ENTRY_ACL_USER, 402, "user402" },
157 #endif
158 
159 	/* One entry for each qualifier. */
160 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY,
161 	  ARCHIVE_ENTRY_ACL_USER, 501, "user501" },
162 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY,
163 	  ARCHIVE_ENTRY_ACL_GROUP, 502, "group502" },
164 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY,
165 	  ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" },
166 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY,
167 	  ARCHIVE_ENTRY_ACL_EVERYONE, -1, "" }
168 };
169 
170 static void
set_acls(struct archive_entry * ae,struct myacl_t * acls,int start,int end)171 set_acls(struct archive_entry *ae, struct myacl_t *acls, int start, int end)
172 {
173 	int i;
174 
175 	archive_entry_acl_clear(ae);
176 	if (start > 0) {
177 		assertEqualInt(ARCHIVE_OK,
178 			archive_entry_acl_add_entry(ae,
179 			    acls[0].type, acls[0].permset, acls[0].tag,
180 			    acls[0].qual, acls[0].name));
181 	}
182 	for (i = start; i < end; i++) {
183 		assertEqualInt(ARCHIVE_OK,
184 		    archive_entry_acl_add_entry(ae,
185 			acls[i].type, acls[i].permset, acls[i].tag,
186 			acls[i].qual, acls[i].name));
187 	}
188 }
189 
190 static int
acl_permset_to_bitmap(acl_permset_t opaque_ps)191 acl_permset_to_bitmap(acl_permset_t opaque_ps)
192 {
193 	static struct { int machine; int portable; } perms[] = {
194 		{ACL_EXECUTE, ARCHIVE_ENTRY_ACL_EXECUTE},
195 		{ACL_WRITE, ARCHIVE_ENTRY_ACL_WRITE},
196 		{ACL_READ, ARCHIVE_ENTRY_ACL_READ},
197 		{ACL_READ_DATA, ARCHIVE_ENTRY_ACL_READ_DATA},
198 		{ACL_LIST_DIRECTORY, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY},
199 		{ACL_WRITE_DATA, ARCHIVE_ENTRY_ACL_WRITE_DATA},
200 		{ACL_ADD_FILE, ARCHIVE_ENTRY_ACL_ADD_FILE},
201 		{ACL_APPEND_DATA, ARCHIVE_ENTRY_ACL_APPEND_DATA},
202 		{ACL_ADD_SUBDIRECTORY, ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY},
203 		{ACL_READ_NAMED_ATTRS, ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS},
204 		{ACL_WRITE_NAMED_ATTRS, ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS},
205 		{ACL_DELETE_CHILD, ARCHIVE_ENTRY_ACL_DELETE_CHILD},
206 		{ACL_READ_ATTRIBUTES, ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES},
207 		{ACL_WRITE_ATTRIBUTES, ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES},
208 		{ACL_DELETE, ARCHIVE_ENTRY_ACL_DELETE},
209 		{ACL_READ_ACL, ARCHIVE_ENTRY_ACL_READ_ACL},
210 		{ACL_WRITE_ACL, ARCHIVE_ENTRY_ACL_WRITE_ACL},
211 		{ACL_WRITE_OWNER, ARCHIVE_ENTRY_ACL_WRITE_OWNER},
212 		{ACL_SYNCHRONIZE, ARCHIVE_ENTRY_ACL_SYNCHRONIZE}
213 	};
214 	int i, permset = 0;
215 
216 	for (i = 0; i < (int)(sizeof(perms)/sizeof(perms[0])); ++i)
217 		if (acl_get_perm_np(opaque_ps, perms[i].machine))
218 			permset |= perms[i].portable;
219 	return permset;
220 }
221 
222 static int
acl_flagset_to_bitmap(acl_flagset_t opaque_fs)223 acl_flagset_to_bitmap(acl_flagset_t opaque_fs)
224 {
225 	static struct { int machine; int portable; } flags[] = {
226 		{ACL_ENTRY_FILE_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT},
227 		{ACL_ENTRY_DIRECTORY_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT},
228 		{ACL_ENTRY_NO_PROPAGATE_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT},
229 		{ACL_ENTRY_INHERIT_ONLY, ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY},
230 	};
231 	int i, flagset = 0;
232 
233 	for (i = 0; i < (int)(sizeof(flags)/sizeof(flags[0])); ++i)
234 		if (acl_get_flag_np(opaque_fs, flags[i].machine))
235 			flagset |= flags[i].portable;
236 	return flagset;
237 }
238 
239 static int
acl_match(acl_entry_t aclent,struct myacl_t * myacl)240 acl_match(acl_entry_t aclent, struct myacl_t *myacl)
241 {
242 	gid_t g, *gp;
243 	uid_t u, *up;
244 	acl_tag_t tag_type;
245 	acl_permset_t opaque_ps;
246 	acl_flagset_t opaque_fs;
247 	int perms;
248 
249 	acl_get_tag_type(aclent, &tag_type);
250 
251 	/* translate the silly opaque permset to a bitmap */
252 	acl_get_permset(aclent, &opaque_ps);
253 	acl_get_flagset_np(aclent, &opaque_fs);
254 	perms = acl_permset_to_bitmap(opaque_ps) | acl_flagset_to_bitmap(opaque_fs);
255 	if (perms != myacl->permset)
256 		return (0);
257 
258 	switch (tag_type) {
259 	case ACL_USER_OBJ:
260 		if (myacl->tag != ARCHIVE_ENTRY_ACL_USER_OBJ) return (0);
261 		break;
262 	case ACL_USER:
263 		if (myacl->tag != ARCHIVE_ENTRY_ACL_USER)
264 			return (0);
265 		up = acl_get_qualifier(aclent);
266 		u = *up;
267 		acl_free(up);
268 		if ((uid_t)myacl->qual != u)
269 			return (0);
270 		break;
271 	case ACL_GROUP_OBJ:
272 		if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP_OBJ) return (0);
273 		break;
274 	case ACL_GROUP:
275 		if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP)
276 			return (0);
277 		gp = acl_get_qualifier(aclent);
278 		g = *gp;
279 		acl_free(gp);
280 		if ((gid_t)myacl->qual != g)
281 			return (0);
282 		break;
283 	case ACL_MASK:
284 		if (myacl->tag != ARCHIVE_ENTRY_ACL_MASK) return (0);
285 		break;
286 	case ACL_EVERYONE:
287 		if (myacl->tag != ARCHIVE_ENTRY_ACL_EVERYONE) return (0);
288 		break;
289 	}
290 	return (1);
291 }
292 
293 static void
compare_acls(acl_t acl,struct myacl_t * myacls,const char * filename,int start,int end)294 compare_acls(acl_t acl, struct myacl_t *myacls, const char *filename, int start, int end)
295 {
296 	int *marker;
297 	int entry_id = ACL_FIRST_ENTRY;
298 	int matched;
299 	int i, n;
300 	acl_entry_t acl_entry;
301 
302 	n = end - start;
303 	marker = malloc(sizeof(marker[0]) * (n + 1));
304 	for (i = 0; i < n; i++)
305 		marker[i] = i + start;
306 	/* Always include the first ACE. */
307 	if (start > 0) {
308 	  marker[n] = 0;
309 	  ++n;
310 	}
311 
312 	/*
313 	 * Iterate over acls in system acl object, try to match each
314 	 * one with an item in the myacls array.
315 	 */
316 	while (1 == acl_get_entry(acl, entry_id, &acl_entry)) {
317 		/* After the first time... */
318 		entry_id = ACL_NEXT_ENTRY;
319 
320 		/* Search for a matching entry (tag and qualifier) */
321 		for (i = 0, matched = 0; i < n && !matched; i++) {
322 			if (acl_match(acl_entry, &myacls[marker[i]])) {
323 				/* We found a match; remove it. */
324 				marker[i] = marker[n - 1];
325 				n--;
326 				matched = 1;
327 			}
328 		}
329 
330 		failure("ACL entry on file %s that shouldn't be there", filename);
331 		assert(matched == 1);
332 	}
333 
334 	/* Dump entries in the myacls array that weren't in the system acl. */
335 	for (i = 0; i < n; ++i) {
336 		failure(" ACL entry %d missing from %s: "
337 		    "type=%d,permset=%x,tag=%d,qual=%d,name=``%s''\n",
338 		    marker[i], filename,
339 		    myacls[marker[i]].type, myacls[marker[i]].permset,
340 		    myacls[marker[i]].tag, myacls[marker[i]].qual,
341 		    myacls[marker[i]].name);
342 		assert(0); /* Record this as a failure. */
343 	}
344 	free(marker);
345 }
346 
347 static void
compare_entry_acls(struct archive_entry * ae,struct myacl_t * myacls,const char * filename,int start,int end)348 compare_entry_acls(struct archive_entry *ae, struct myacl_t *myacls, const char *filename, int start, int end)
349 {
350 	int *marker;
351 	int matched;
352 	int i, n;
353 	int type, permset, tag, qual;
354 	const char *name;
355 
356 	/* Count ACL entries in myacls array and allocate an indirect array. */
357 	n = end - start;
358 	marker = malloc(sizeof(marker[0]) * (n + 1));
359 	for (i = 0; i < n; i++)
360 		marker[i] = i + start;
361 	/* Always include the first ACE. */
362 	if (start > 0) {
363 	  marker[n] = 0;
364 	  ++n;
365 	}
366 
367 	/*
368 	 * Iterate over acls in entry, try to match each
369 	 * one with an item in the myacls array.
370 	 */
371 	assertEqualInt(n, archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_NFS4));
372 	while (ARCHIVE_OK == archive_entry_acl_next(ae,
373 	    ARCHIVE_ENTRY_ACL_TYPE_NFS4, &type, &permset, &tag, &qual, &name)) {
374 
375 		/* Search for a matching entry (tag and qualifier) */
376 		for (i = 0, matched = 0; i < n && !matched; i++) {
377 			if (tag == myacls[marker[i]].tag
378 			    && qual == myacls[marker[i]].qual
379 			    && permset == myacls[marker[i]].permset
380 			    && type == myacls[marker[i]].type) {
381 				/* We found a match; remove it. */
382 				marker[i] = marker[n - 1];
383 				n--;
384 				matched = 1;
385 			}
386 		}
387 
388 		failure("ACL entry on file that shouldn't be there: "
389 			"type=%d,permset=%x,tag=%d,qual=%d",
390 			type,permset,tag,qual);
391 		assert(matched == 1);
392 	}
393 
394 	/* Dump entries in the myacls array that weren't in the system acl. */
395 	for (i = 0; i < n; ++i) {
396 		failure(" ACL entry %d missing from %s: "
397 		    "type=%d,permset=%x,tag=%d,qual=%d,name=``%s''\n",
398 		    marker[i], filename,
399 		    myacls[marker[i]].type, myacls[marker[i]].permset,
400 		    myacls[marker[i]].tag, myacls[marker[i]].qual,
401 		    myacls[marker[i]].name);
402 		assert(0); /* Record this as a failure. */
403 	}
404 	free(marker);
405 }
406 #endif
407 
408 /*
409  * Verify ACL restore-to-disk.  This test is FreeBSD-specific.
410  */
411 
DEFINE_TEST(test_acl_freebsd_nfs4)412 DEFINE_TEST(test_acl_freebsd_nfs4)
413 {
414 #if !defined(__FreeBSD__)
415 	skipping("FreeBSD-specific NFS4 ACL restore test");
416 #elif __FreeBSD__ < 8
417 	skipping("NFS4 ACLs supported only on FreeBSD 8.0 and later");
418 #else
419 	char buff[64];
420 	struct stat st;
421 	struct archive *a;
422 	struct archive_entry *ae;
423 	int i, n;
424 	acl_t acl;
425 
426 	/*
427 	 * First, do a quick manual set/read of ACL data to
428 	 * verify that the local filesystem does support ACLs.
429 	 * If it doesn't, we'll simply skip the remaining tests.
430 	 */
431 	acl = acl_from_text("owner@:rwxp::allow,group@:rwp:f:allow");
432 	assert((void *)acl != NULL);
433 	/* Create a test dir and try to set an ACL on it. */
434 	if (!assertMakeDir("pretest", 0755)) {
435 		acl_free(acl);
436 		return;
437 	}
438 
439 	n = acl_set_file("pretest", ACL_TYPE_NFS4, acl);
440 	acl_free(acl);
441 	if (n != 0 && errno == EOPNOTSUPP) {
442 		skipping("NFS4 ACL tests require that NFS4 ACLs"
443 		    " be enabled on the filesystem");
444 		return;
445 	}
446 	if (n != 0 && errno == EINVAL) {
447 		skipping("This filesystem does not support NFS4 ACLs");
448 		return;
449 	}
450 	failure("acl_set_file(): errno = %d (%s)",
451 	    errno, strerror(errno));
452 	assertEqualInt(0, n);
453 
454 	/* Create a write-to-disk object. */
455 	assert(NULL != (a = archive_write_disk_new()));
456 	archive_write_disk_set_options(a,
457 	    ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_ACL);
458 
459 	/* Populate an archive entry with some metadata, including ACL info */
460 	ae = archive_entry_new();
461 	assert(ae != NULL);
462 	archive_entry_set_pathname(ae, "testall");
463 	archive_entry_set_filetype(ae, AE_IFREG);
464 	archive_entry_set_perm(ae, 0654);
465 	archive_entry_set_mtime(ae, 123456, 7890);
466 	archive_entry_set_size(ae, 0);
467 	set_acls(ae, acls_reg, 0, (int)(sizeof(acls_reg)/sizeof(acls_reg[0])));
468 
469 	/* Write the entry to disk, including ACLs. */
470 	assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
471 
472 	/* Likewise for a dir. */
473 	archive_entry_set_pathname(ae, "dirall");
474 	archive_entry_set_filetype(ae, AE_IFDIR);
475 	archive_entry_set_perm(ae, 0654);
476 	archive_entry_set_mtime(ae, 123456, 7890);
477 	set_acls(ae, acls_dir, 0, (int)(sizeof(acls_dir)/sizeof(acls_dir[0])));
478 	assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
479 
480 	for (i = 0; i < (int)(sizeof(acls_dir)/sizeof(acls_dir[0])); ++i) {
481 	  sprintf(buff, "dir%d", i);
482 	  archive_entry_set_pathname(ae, buff);
483 	  archive_entry_set_filetype(ae, AE_IFDIR);
484 	  archive_entry_set_perm(ae, 0654);
485 	  archive_entry_set_mtime(ae, 123456 + i, 7891 + i);
486 	  set_acls(ae, acls_dir, i, i + 1);
487 	  assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
488 	}
489 
490 	archive_entry_free(ae);
491 
492 	/* Close the archive. */
493 	assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
494 	assertEqualInt(ARCHIVE_OK, archive_write_free(a));
495 
496 	/* Verify the data on disk. */
497 	assertEqualInt(0, stat("testall", &st));
498 	assertEqualInt(st.st_mtime, 123456);
499 	acl = acl_get_file("testall", ACL_TYPE_NFS4);
500 	assert(acl != (acl_t)NULL);
501 	compare_acls(acl, acls_reg, "testall", 0, (int)(sizeof(acls_reg)/sizeof(acls_reg[0])));
502 	acl_free(acl);
503 
504 	/* Verify single-permission dirs on disk. */
505 	for (i = 0; i < (int)(sizeof(acls_dir)/sizeof(acls_dir[0])); ++i) {
506 	  sprintf(buff, "dir%d", i);
507 	  assertEqualInt(0, stat(buff, &st));
508 	  assertEqualInt(st.st_mtime, 123456 + i);
509 	  acl = acl_get_file(buff, ACL_TYPE_NFS4);
510 	  assert(acl != (acl_t)NULL);
511 	  compare_acls(acl, acls_dir, buff, i, i + 1);
512 	  acl_free(acl);
513 	}
514 
515 	/* Verify "dirall" on disk. */
516 	assertEqualInt(0, stat("dirall", &st));
517 	assertEqualInt(st.st_mtime, 123456);
518 	acl = acl_get_file("dirall", ACL_TYPE_NFS4);
519 	assert(acl != (acl_t)NULL);
520 	compare_acls(acl, acls_dir, "dirall", 0,  (int)(sizeof(acls_dir)/sizeof(acls_dir[0])));
521 	acl_free(acl);
522 
523 	/* Read and compare ACL via archive_read_disk */
524 	a = archive_read_disk_new();
525 	assert(a != NULL);
526 	ae = archive_entry_new();
527 	assert(ae != NULL);
528 	archive_entry_set_pathname(ae, "testall");
529 	assertEqualInt(ARCHIVE_OK,
530 		       archive_read_disk_entry_from_file(a, ae, -1, NULL));
531 	compare_entry_acls(ae, acls_reg, "testall", 0, (int)(sizeof(acls_reg)/sizeof(acls_reg[0])));
532 	archive_entry_free(ae);
533 	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
534 
535 	/* Read and compare ACL via archive_read_disk */
536 	a = archive_read_disk_new();
537 	assert(a != NULL);
538 	ae = archive_entry_new();
539 	assert(ae != NULL);
540 	archive_entry_set_pathname(ae, "dirall");
541 	assertEqualInt(ARCHIVE_OK,
542 		       archive_read_disk_entry_from_file(a, ae, -1, NULL));
543 	compare_entry_acls(ae, acls_dir, "dirall", 0,  (int)(sizeof(acls_dir)/sizeof(acls_dir[0])));
544 	archive_entry_free(ae);
545 	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
546 #endif
547 }
548