test_acl_platform_nfs4.c revision 313571
1/*-
2 * Copyright (c) 2003-2010 Tim Kientzle
3 * Copyright (c) 2017 Martin Matuska
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26#include "test.h"
27__FBSDID("$FreeBSD$");
28
29#if HAVE_POSIX_ACL || HAVE_NFS4_ACL
30#define _ACL_PRIVATE
31#include <sys/acl.h>
32#if HAVE_DARWIN_ACL
33#include <membership.h>
34#endif
35#endif
36
37#if HAVE_NFS4_ACL
38struct myacl_t {
39	int type;
40	int permset;
41	int tag;
42	int qual; /* GID or UID of user/group, depending on tag. */
43	const char *name; /* Name of user/group, depending on tag. */
44};
45
46static struct myacl_t acls_reg[] = {
47#if !HAVE_DARWIN_ACL
48	/* For this test, we need the file owner to be able to read and write the ACL. */
49	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
50	  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,
51	  ARCHIVE_ENTRY_ACL_USER_OBJ, -1, ""},
52#endif
53	/* An entry for each type. */
54	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE,
55	  ARCHIVE_ENTRY_ACL_USER, 108, "user108" },
56	{ ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_EXECUTE,
57	  ARCHIVE_ENTRY_ACL_USER, 109, "user109" },
58
59	/* An entry for each permission. */
60	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE,
61	  ARCHIVE_ENTRY_ACL_USER, 112, "user112" },
62	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_DATA,
63	  ARCHIVE_ENTRY_ACL_USER, 113, "user113" },
64	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_DATA,
65	  ARCHIVE_ENTRY_ACL_USER, 115, "user115" },
66	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_APPEND_DATA,
67	  ARCHIVE_ENTRY_ACL_USER, 117, "user117" },
68	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS,
69	  ARCHIVE_ENTRY_ACL_USER, 119, "user119" },
70	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS,
71	  ARCHIVE_ENTRY_ACL_USER, 120, "user120" },
72	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES,
73	  ARCHIVE_ENTRY_ACL_USER, 122, "user122" },
74	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES,
75	  ARCHIVE_ENTRY_ACL_USER, 123, "user123" },
76	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_DELETE,
77	  ARCHIVE_ENTRY_ACL_USER, 124, "user124" },
78	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_ACL,
79	  ARCHIVE_ENTRY_ACL_USER, 125, "user125" },
80	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_ACL,
81	  ARCHIVE_ENTRY_ACL_USER, 126, "user126" },
82	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_OWNER,
83	  ARCHIVE_ENTRY_ACL_USER, 127, "user127" },
84	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_SYNCHRONIZE,
85	  ARCHIVE_ENTRY_ACL_USER, 128, "user128" },
86
87	/* One entry for each qualifier. */
88	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE,
89	  ARCHIVE_ENTRY_ACL_USER, 135, "user135" },
90//	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE,
91//	  ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" },
92	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE,
93	  ARCHIVE_ENTRY_ACL_GROUP, 136, "group136" },
94#if !HAVE_DARWIN_ACL
95	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE,
96	  ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" },
97	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE,
98	  ARCHIVE_ENTRY_ACL_EVERYONE, -1, "" }
99#else	/* MacOS - mode 0654 */
100	{ ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_EXECUTE,
101	  ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" },
102	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
103	    ARCHIVE_ENTRY_ACL_READ_DATA |
104	    ARCHIVE_ENTRY_ACL_WRITE_DATA |
105	    ARCHIVE_ENTRY_ACL_APPEND_DATA |
106	    ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES |
107	    ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES |
108	    ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS |
109	    ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS |
110	    ARCHIVE_ENTRY_ACL_READ_ACL |
111	    ARCHIVE_ENTRY_ACL_WRITE_ACL |
112	    ARCHIVE_ENTRY_ACL_WRITE_OWNER |
113	    ARCHIVE_ENTRY_ACL_SYNCHRONIZE,
114	  ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" },
115	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
116	    ARCHIVE_ENTRY_ACL_READ_DATA |
117	    ARCHIVE_ENTRY_ACL_EXECUTE |
118	    ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES |
119	    ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS |
120	    ARCHIVE_ENTRY_ACL_READ_ACL |
121	    ARCHIVE_ENTRY_ACL_SYNCHRONIZE,
122	  ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" },
123	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
124	    ARCHIVE_ENTRY_ACL_READ_DATA |
125	    ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES |
126	    ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS |
127	    ARCHIVE_ENTRY_ACL_READ_ACL |
128	    ARCHIVE_ENTRY_ACL_SYNCHRONIZE,
129	  ARCHIVE_ENTRY_ACL_EVERYONE, -1, "" }
130#endif
131};
132
133static const int acls_reg_cnt = (int)(sizeof(acls_reg)/sizeof(acls_reg[0]));
134
135static struct myacl_t acls_dir[] = {
136	/* For this test, we need to be able to read and write the ACL. */
137#if !HAVE_DARWIN_ACL
138	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_READ_ACL,
139	  ARCHIVE_ENTRY_ACL_USER_OBJ, -1, ""},
140#endif
141
142	/* An entry for each type. */
143	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY,
144	  ARCHIVE_ENTRY_ACL_USER, 101, "user101" },
145	{ ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY,
146	  ARCHIVE_ENTRY_ACL_USER, 102, "user102" },
147
148	/* An entry for each permission. */
149	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY,
150	  ARCHIVE_ENTRY_ACL_USER, 201, "user201" },
151	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_ADD_FILE,
152	  ARCHIVE_ENTRY_ACL_USER, 202, "user202" },
153	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY,
154	  ARCHIVE_ENTRY_ACL_USER, 203, "user203" },
155	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS,
156	  ARCHIVE_ENTRY_ACL_USER, 204, "user204" },
157	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS,
158	  ARCHIVE_ENTRY_ACL_USER, 205, "user205" },
159	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_DELETE_CHILD,
160	  ARCHIVE_ENTRY_ACL_USER, 206, "user206" },
161	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES,
162	  ARCHIVE_ENTRY_ACL_USER, 207, "user207" },
163	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES,
164	  ARCHIVE_ENTRY_ACL_USER, 208, "user208" },
165	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_DELETE,
166	  ARCHIVE_ENTRY_ACL_USER, 209, "user209" },
167	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_ACL,
168	  ARCHIVE_ENTRY_ACL_USER, 210, "user210" },
169	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_ACL,
170	  ARCHIVE_ENTRY_ACL_USER, 211, "user211" },
171	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_OWNER,
172	  ARCHIVE_ENTRY_ACL_USER, 212, "user212" },
173	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_SYNCHRONIZE,
174	  ARCHIVE_ENTRY_ACL_USER, 213, "user213" },
175
176	/* One entry with each inheritance value. */
177	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
178	  ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT,
179	  ARCHIVE_ENTRY_ACL_USER, 301, "user301" },
180	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
181	  ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT,
182	  ARCHIVE_ENTRY_ACL_USER, 302, "user302" },
183#if 0
184	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
185	  ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT,
186	  ARCHIVE_ENTRY_ACL_USER, 303, "user303" },
187	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
188	  ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY,
189	  ARCHIVE_ENTRY_ACL_USER, 304, "user304" },
190	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
191	  ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_INHERITED,
192	  ARCHIVE_ENTRY_ACL_USER, 305, "user305" },
193#endif
194
195#if 0
196	/* FreeBSD does not support audit entries. */
197	{ ARCHIVE_ENTRY_ACL_TYPE_AUDIT,
198	  ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS,
199	  ARCHIVE_ENTRY_ACL_USER, 401, "user401" },
200	{ ARCHIVE_ENTRY_ACL_TYPE_AUDIT,
201	  ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS,
202	  ARCHIVE_ENTRY_ACL_USER, 402, "user402" },
203#endif
204
205	/* One entry for each qualifier. */
206	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY,
207	  ARCHIVE_ENTRY_ACL_USER, 501, "user501" },
208	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY,
209	  ARCHIVE_ENTRY_ACL_GROUP, 502, "group502" },
210#if !HAVE_DARWIN_ACL
211	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY,
212	  ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" },
213	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY,
214	  ARCHIVE_ENTRY_ACL_EVERYONE, -1, "" }
215#else	/* MacOS - mode 0654 */
216	{ ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_EXECUTE,
217	  ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" },
218	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
219	    ARCHIVE_ENTRY_ACL_READ_DATA |
220	    ARCHIVE_ENTRY_ACL_WRITE_DATA |
221	    ARCHIVE_ENTRY_ACL_APPEND_DATA |
222	    ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES |
223	    ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES |
224	    ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS |
225	    ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS |
226	    ARCHIVE_ENTRY_ACL_READ_ACL |
227	    ARCHIVE_ENTRY_ACL_WRITE_ACL |
228	    ARCHIVE_ENTRY_ACL_WRITE_OWNER |
229	    ARCHIVE_ENTRY_ACL_SYNCHRONIZE,
230	  ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" },
231	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
232	    ARCHIVE_ENTRY_ACL_READ_DATA |
233	    ARCHIVE_ENTRY_ACL_EXECUTE |
234	    ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES |
235	    ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS |
236	    ARCHIVE_ENTRY_ACL_READ_ACL |
237	    ARCHIVE_ENTRY_ACL_SYNCHRONIZE,
238	  ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" },
239	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
240	    ARCHIVE_ENTRY_ACL_READ_DATA |
241	    ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES |
242	    ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS |
243	    ARCHIVE_ENTRY_ACL_READ_ACL |
244	    ARCHIVE_ENTRY_ACL_SYNCHRONIZE,
245	  ARCHIVE_ENTRY_ACL_EVERYONE, -1, "" }
246#endif
247};
248
249static const int acls_dir_cnt = (int)(sizeof(acls_dir)/sizeof(acls_dir[0]));
250
251static void
252set_acls(struct archive_entry *ae, struct myacl_t *acls, int start, int end)
253{
254	int i;
255
256	archive_entry_acl_clear(ae);
257	if (start > 0) {
258		assertEqualInt(ARCHIVE_OK,
259			archive_entry_acl_add_entry(ae,
260			    acls[0].type, acls[0].permset, acls[0].tag,
261			    acls[0].qual, acls[0].name));
262	}
263	for (i = start; i < end; i++) {
264		assertEqualInt(ARCHIVE_OK,
265		    archive_entry_acl_add_entry(ae,
266			acls[i].type, acls[i].permset, acls[i].tag,
267			acls[i].qual, acls[i].name));
268	}
269}
270
271static int
272#ifdef HAVE_SUN_ACL
273acl_permset_to_bitmap(uint32_t a_access_mask)
274#else
275acl_permset_to_bitmap(acl_permset_t opaque_ps)
276#endif
277{
278	static struct { int machine; int portable; } perms[] = {
279#ifdef HAVE_SUN_ACL	/* Solaris NFSv4 ACL permissions */
280		{ACE_EXECUTE, ARCHIVE_ENTRY_ACL_EXECUTE},
281		{ACE_READ_DATA, ARCHIVE_ENTRY_ACL_READ_DATA},
282		{ACE_LIST_DIRECTORY, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY},
283		{ACE_WRITE_DATA, ARCHIVE_ENTRY_ACL_WRITE_DATA},
284		{ACE_ADD_FILE, ARCHIVE_ENTRY_ACL_ADD_FILE},
285		{ACE_APPEND_DATA, ARCHIVE_ENTRY_ACL_APPEND_DATA},
286		{ACE_ADD_SUBDIRECTORY, ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY},
287		{ACE_READ_NAMED_ATTRS, ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS},
288		{ACE_WRITE_NAMED_ATTRS, ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS},
289		{ACE_DELETE_CHILD, ARCHIVE_ENTRY_ACL_DELETE_CHILD},
290		{ACE_READ_ATTRIBUTES, ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES},
291		{ACE_WRITE_ATTRIBUTES, ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES},
292		{ACE_DELETE, ARCHIVE_ENTRY_ACL_DELETE},
293		{ACE_READ_ACL, ARCHIVE_ENTRY_ACL_READ_ACL},
294		{ACE_WRITE_ACL, ARCHIVE_ENTRY_ACL_WRITE_ACL},
295		{ACE_WRITE_OWNER, ARCHIVE_ENTRY_ACL_WRITE_OWNER},
296		{ACE_SYNCHRONIZE, ARCHIVE_ENTRY_ACL_SYNCHRONIZE}
297#elif HAVE_DARWIN_ACL	/* MacOS NFSv4 ACL permissions */
298		{ACL_READ_DATA, ARCHIVE_ENTRY_ACL_READ_DATA},
299		{ACL_LIST_DIRECTORY, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY},
300		{ACL_WRITE_DATA, ARCHIVE_ENTRY_ACL_WRITE_DATA},
301		{ACL_ADD_FILE, ARCHIVE_ENTRY_ACL_ADD_FILE},
302		{ACL_EXECUTE, ARCHIVE_ENTRY_ACL_EXECUTE},
303		{ACL_DELETE, ARCHIVE_ENTRY_ACL_DELETE},
304		{ACL_APPEND_DATA, ARCHIVE_ENTRY_ACL_APPEND_DATA},
305		{ACL_ADD_SUBDIRECTORY, ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY},
306		{ACL_DELETE_CHILD, ARCHIVE_ENTRY_ACL_DELETE_CHILD},
307		{ACL_READ_ATTRIBUTES, ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES},
308		{ACL_WRITE_ATTRIBUTES, ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES},
309		{ACL_READ_EXTATTRIBUTES, ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS},
310		{ACL_WRITE_EXTATTRIBUTES, ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS},
311		{ACL_READ_SECURITY, ARCHIVE_ENTRY_ACL_READ_ACL},
312		{ACL_WRITE_SECURITY, ARCHIVE_ENTRY_ACL_WRITE_ACL},
313		{ACL_CHANGE_OWNER, ARCHIVE_ENTRY_ACL_WRITE_OWNER},
314		{ACL_SYNCHRONIZE, ARCHIVE_ENTRY_ACL_SYNCHRONIZE},
315#else	/* FreeBSD NFSv4 ACL permissions */
316		{ACL_EXECUTE, ARCHIVE_ENTRY_ACL_EXECUTE},
317		{ACL_WRITE, ARCHIVE_ENTRY_ACL_WRITE},
318		{ACL_READ, ARCHIVE_ENTRY_ACL_READ},
319		{ACL_READ_DATA, ARCHIVE_ENTRY_ACL_READ_DATA},
320		{ACL_LIST_DIRECTORY, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY},
321		{ACL_WRITE_DATA, ARCHIVE_ENTRY_ACL_WRITE_DATA},
322		{ACL_ADD_FILE, ARCHIVE_ENTRY_ACL_ADD_FILE},
323		{ACL_APPEND_DATA, ARCHIVE_ENTRY_ACL_APPEND_DATA},
324		{ACL_ADD_SUBDIRECTORY, ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY},
325		{ACL_READ_NAMED_ATTRS, ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS},
326		{ACL_WRITE_NAMED_ATTRS, ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS},
327		{ACL_DELETE_CHILD, ARCHIVE_ENTRY_ACL_DELETE_CHILD},
328		{ACL_READ_ATTRIBUTES, ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES},
329		{ACL_WRITE_ATTRIBUTES, ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES},
330		{ACL_DELETE, ARCHIVE_ENTRY_ACL_DELETE},
331		{ACL_READ_ACL, ARCHIVE_ENTRY_ACL_READ_ACL},
332		{ACL_WRITE_ACL, ARCHIVE_ENTRY_ACL_WRITE_ACL},
333		{ACL_WRITE_OWNER, ARCHIVE_ENTRY_ACL_WRITE_OWNER},
334		{ACL_SYNCHRONIZE, ARCHIVE_ENTRY_ACL_SYNCHRONIZE}
335#endif
336	};
337	int i, permset = 0;
338
339	for (i = 0; i < (int)(sizeof(perms)/sizeof(perms[0])); ++i)
340#if HAVE_SUN_ACL
341		if (a_access_mask & perms[i].machine)
342#else
343		if (acl_get_perm_np(opaque_ps, perms[i].machine))
344#endif
345			permset |= perms[i].portable;
346	return permset;
347}
348
349static int
350#if HAVE_SUN_ACL
351acl_flagset_to_bitmap(uint16_t a_flags)
352#else
353acl_flagset_to_bitmap(acl_flagset_t opaque_fs)
354#endif
355{
356	static struct { int machine; int portable; } flags[] = {
357#if HAVE_SUN_ACL	/* Solaris NFSv4 ACL inheritance flags */
358		{ACE_FILE_INHERIT_ACE, ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT},
359		{ACE_DIRECTORY_INHERIT_ACE, ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT},
360		{ACE_NO_PROPAGATE_INHERIT_ACE, ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT},
361		{ACE_INHERIT_ONLY_ACE, ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY},
362		{ACE_SUCCESSFUL_ACCESS_ACE_FLAG, ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS},
363		{ACE_FAILED_ACCESS_ACE_FLAG, ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS},
364		{ACE_INHERITED_ACE, ARCHIVE_ENTRY_ACL_ENTRY_INHERITED}
365#elif HAVE_DARWIN_ACL	/* MacOS NFSv4 ACL inheritance flags */
366		{ACL_ENTRY_INHERITED, ARCHIVE_ENTRY_ACL_ENTRY_INHERITED},
367		{ACL_ENTRY_FILE_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT},
368		{ACL_ENTRY_DIRECTORY_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT},
369		{ACL_ENTRY_LIMIT_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT},
370		{ACL_ENTRY_ONLY_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY}
371#else	/* FreeBSD NFSv4 ACL inheritance flags */
372		{ACL_ENTRY_FILE_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT},
373		{ACL_ENTRY_DIRECTORY_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT},
374		{ACL_ENTRY_NO_PROPAGATE_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT},
375		{ACL_ENTRY_SUCCESSFUL_ACCESS, ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS},
376		{ACL_ENTRY_NO_PROPAGATE_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS},
377		{ACL_ENTRY_INHERIT_ONLY, ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY},
378#endif
379	};
380	int i, flagset = 0;
381
382	for (i = 0; i < (int)(sizeof(flags)/sizeof(flags[0])); ++i)
383#if HAVE_SUN_ACL
384		if (a_flags & flags[i].machine)
385#else
386		if (acl_get_flag_np(opaque_fs, flags[i].machine))
387#endif
388			flagset |= flags[i].portable;
389	return flagset;
390}
391
392static int
393#if HAVE_SUN_ACL
394acl_match(ace_t *ace, struct myacl_t *myacl)
395#else
396acl_match(acl_entry_t aclent, struct myacl_t *myacl)
397#endif
398{
399#if !HAVE_SUN_ACL
400#if HAVE_DARWIN_ACL
401	void *q;
402	uid_t ugid;
403	int r, idtype;
404#else
405	gid_t g, *gp;
406	uid_t u, *up;
407	acl_entry_type_t entry_type;
408#endif	/* !HAVE_DARWIN_ACL */
409	acl_tag_t tag_type;
410	acl_permset_t opaque_ps;
411	acl_flagset_t opaque_fs;
412#endif	/* !HAVE_SUN_ACL */
413	int perms;
414
415#if HAVE_SUN_ACL
416	perms = acl_permset_to_bitmap(ace->a_access_mask) | acl_flagset_to_bitmap(ace->a_flags);
417#else
418	acl_get_tag_type(aclent, &tag_type);
419#if !HAVE_DARWIN_ACL
420	acl_get_entry_type_np(aclent, &entry_type);
421#endif
422
423	/* translate the silly opaque permset to a bitmap */
424	acl_get_permset(aclent, &opaque_ps);
425	acl_get_flagset_np(aclent, &opaque_fs);
426	perms = acl_permset_to_bitmap(opaque_ps) | acl_flagset_to_bitmap(opaque_fs);
427#endif
428	if (perms != myacl->permset)
429		return (0);
430
431#if HAVE_SUN_ACL
432	switch (ace->a_type) {
433	case ACE_ACCESS_ALLOWED_ACE_TYPE:
434		if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_ALLOW)
435			return (0);
436		break;
437	case ACE_ACCESS_DENIED_ACE_TYPE:
438		if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_DENY)
439			return (0);
440		break;
441	case ACE_SYSTEM_AUDIT_ACE_TYPE:
442		if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_AUDIT)
443			return (0);
444		break;
445	case ACE_SYSTEM_ALARM_ACE_TYPE:
446		if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_ALARM)
447			return (0);
448		break;
449	default:
450		return (0);
451	}
452
453	if (ace->a_flags & ACE_OWNER) {
454		if (myacl->tag != ARCHIVE_ENTRY_ACL_USER_OBJ)
455			return (0);
456	} else if (ace->a_flags & ACE_GROUP) {
457		if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP_OBJ)
458			return (0);
459	} else if (ace->a_flags & ACE_EVERYONE) {
460		if (myacl->tag != ARCHIVE_ENTRY_ACL_EVERYONE)
461			return (0);
462	} else if (ace->a_flags & ACE_IDENTIFIER_GROUP) {
463		if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP)
464			return (0);
465		if ((gid_t)myacl->qual != ace->a_who)
466			return (0);
467	} else {
468		if (myacl->tag != ARCHIVE_ENTRY_ACL_USER)
469			return (0);
470		if ((uid_t)myacl->qual != ace->a_who)
471			return (0);
472	}
473#elif HAVE_DARWIN_ACL
474	r = 0;
475	switch (tag_type) {
476	case ACL_EXTENDED_ALLOW:
477		if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_ALLOW)
478			return (0);
479		break;
480	case ACL_EXTENDED_DENY:
481		if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_DENY)
482			return (0);
483		break;
484	default:
485		return (0);
486	}
487	q = acl_get_qualifier(aclent);
488	if (q == NULL)
489		return (0);
490	r = mbr_uuid_to_id((const unsigned char *)q, &ugid, &idtype);
491	acl_free(q);
492	if (r != 0)
493		return (0);
494	switch (idtype) {
495		case ID_TYPE_UID:
496			if (myacl->tag != ARCHIVE_ENTRY_ACL_USER)
497				return (0);
498			if ((uid_t)myacl->qual != ugid)
499				return (0);
500			break;
501		case ID_TYPE_GID:
502			if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP)
503				return (0);
504			if ((gid_t)myacl->qual != ugid)
505				return (0);
506			break;
507		default:
508			return (0);
509	}
510#else	/* !HAVE_SUN_ACL && !HAVE_DARWIN_ACL */
511	switch (entry_type) {
512	case ACL_ENTRY_TYPE_ALLOW:
513		if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_ALLOW)
514			return (0);
515		break;
516	case ACL_ENTRY_TYPE_DENY:
517		if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_DENY)
518			return (0);
519		break;
520	case ACL_ENTRY_TYPE_AUDIT:
521		if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_AUDIT)
522			return (0);
523	case ACL_ENTRY_TYPE_ALARM:
524		if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_ALARM)
525			return (0);
526	default:
527		return (0);
528	}
529
530	switch (tag_type) {
531	case ACL_USER_OBJ:
532		if (myacl->tag != ARCHIVE_ENTRY_ACL_USER_OBJ) return (0);
533		break;
534	case ACL_USER:
535		if (myacl->tag != ARCHIVE_ENTRY_ACL_USER)
536			return (0);
537		up = acl_get_qualifier(aclent);
538		u = *up;
539		acl_free(up);
540		if ((uid_t)myacl->qual != u)
541			return (0);
542		break;
543	case ACL_GROUP_OBJ:
544		if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP_OBJ) return (0);
545		break;
546	case ACL_GROUP:
547		if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP)
548			return (0);
549		gp = acl_get_qualifier(aclent);
550		g = *gp;
551		acl_free(gp);
552		if ((gid_t)myacl->qual != g)
553			return (0);
554		break;
555	case ACL_MASK:
556		if (myacl->tag != ARCHIVE_ENTRY_ACL_MASK) return (0);
557		break;
558	case ACL_EVERYONE:
559		if (myacl->tag != ARCHIVE_ENTRY_ACL_EVERYONE) return (0);
560		break;
561	}
562#endif	/* !HAVE_SUN_ACL && !HAVE_DARWIN_ACL */
563	return (1);
564}
565
566static void
567compare_acls(
568#if HAVE_SUN_ACL
569    acl_t *acl,
570#else
571    acl_t acl,
572#endif
573    struct myacl_t *myacls, const char *filename, int start, int end)
574{
575	int *marker;
576	int matched;
577	int i, n;
578#if HAVE_SUN_ACL
579	int e;
580	ace_t *acl_entry;
581#else
582	int entry_id = ACL_FIRST_ENTRY;
583	acl_entry_t acl_entry;
584#endif
585
586	n = end - start;
587	marker = malloc(sizeof(marker[0]) * (n + 1));
588	for (i = 0; i < n; i++)
589		marker[i] = i + start;
590	/* Always include the first ACE. */
591	if (start > 0) {
592	  marker[n] = 0;
593	  ++n;
594	}
595
596	/*
597	 * Iterate over acls in system acl object, try to match each
598	 * one with an item in the myacls array.
599	 */
600#if HAVE_SUN_ACL
601	for (e = 0; e < acl->acl_cnt; e++)
602#elif HAVE_DARWIN_ACL
603	while (0 == acl_get_entry(acl, entry_id, &acl_entry))
604#else
605	while (1 == acl_get_entry(acl, entry_id, &acl_entry))
606#endif
607	{
608#if HAVE_SUN_ACL
609		acl_entry = &((ace_t *)acl->acl_aclp)[e];
610#else
611		/* After the first time... */
612		entry_id = ACL_NEXT_ENTRY;
613#endif
614		/* Search for a matching entry (tag and qualifier) */
615		for (i = 0, matched = 0; i < n && !matched; i++) {
616			if (acl_match(acl_entry, &myacls[marker[i]])) {
617				/* We found a match; remove it. */
618				marker[i] = marker[n - 1];
619				n--;
620				matched = 1;
621			}
622		}
623
624		failure("ACL entry on file %s that shouldn't be there",
625		    filename);
626		assert(matched == 1);
627	}
628
629	/* Dump entries in the myacls array that weren't in the system acl. */
630	for (i = 0; i < n; ++i) {
631		failure(" ACL entry %d missing from %s: "
632		    "type=%#010x,permset=%#010x,tag=%d,qual=%d,name=``%s''\n",
633		    marker[i], filename,
634		    myacls[marker[i]].type, myacls[marker[i]].permset,
635		    myacls[marker[i]].tag, myacls[marker[i]].qual,
636		    myacls[marker[i]].name);
637		assert(0); /* Record this as a failure. */
638	}
639	free(marker);
640}
641
642static void
643compare_entry_acls(struct archive_entry *ae, struct myacl_t *myacls, const char *filename, int start, int end)
644{
645	int *marker;
646	int matched;
647	int i, n;
648	int type, permset, tag, qual;
649	const char *name;
650
651	/* Count ACL entries in myacls array and allocate an indirect array. */
652	n = end - start;
653	marker = malloc(sizeof(marker[0]) * (n + 1));
654	for (i = 0; i < n; i++)
655		marker[i] = i + start;
656	/* Always include the first ACE. */
657	if (start > 0) {
658	  marker[n] = 0;
659	  ++n;
660	}
661
662	/*
663	 * Iterate over acls in entry, try to match each
664	 * one with an item in the myacls array.
665	 */
666	assertEqualInt(n, archive_entry_acl_reset(ae,
667	    ARCHIVE_ENTRY_ACL_TYPE_NFS4));
668	while (ARCHIVE_OK == archive_entry_acl_next(ae,
669	    ARCHIVE_ENTRY_ACL_TYPE_NFS4, &type, &permset, &tag, &qual, &name)) {
670
671		/* Search for a matching entry (tag and qualifier) */
672		for (i = 0, matched = 0; i < n && !matched; i++) {
673			if (tag == myacls[marker[i]].tag
674			    && qual == myacls[marker[i]].qual
675			    && permset == myacls[marker[i]].permset
676			    && type == myacls[marker[i]].type) {
677				/* We found a match; remove it. */
678				marker[i] = marker[n - 1];
679				n--;
680				matched = 1;
681			}
682		}
683
684		failure("ACL entry on file that shouldn't be there: "
685			"type=%#010x,permset=%#010x,tag=%d,qual=%d",
686			type,permset,tag,qual);
687		assert(matched == 1);
688	}
689
690	/* Dump entries in the myacls array that weren't in the system acl. */
691	for (i = 0; i < n; ++i) {
692		failure(" ACL entry %d missing from %s: "
693		    "type=%#010x,permset=%#010x,tag=%d,qual=%d,name=``%s''\n",
694		    marker[i], filename,
695		    myacls[marker[i]].type, myacls[marker[i]].permset,
696		    myacls[marker[i]].tag, myacls[marker[i]].qual,
697		    myacls[marker[i]].name);
698		assert(0); /* Record this as a failure. */
699	}
700	free(marker);
701}
702#endif	/* HAVE_NFS4_ACL */
703
704/*
705 * Verify ACL restore-to-disk.  This test is Platform-specific.
706 */
707
708DEFINE_TEST(test_acl_platform_nfs4)
709{
710#if !HAVE_NFS4_ACL
711	skipping("NFS4 ACLs are not supported on this platform");
712#else
713	char buff[64];
714	struct stat st;
715	struct archive *a;
716	struct archive_entry *ae;
717	int i, n;
718	char *func;
719#if HAVE_DARWIN_ACL /* On MacOS we skip trivial ACLs in some tests */
720	const int regcnt = acls_reg_cnt - 4;
721	const int dircnt = acls_dir_cnt - 4;
722#else
723	const int regcnt = acls_reg_cnt;
724	const int dircnt = acls_dir_cnt;
725#endif
726#if HAVE_SUN_ACL
727	acl_t *acl;
728#else	/* !HAVE_SUN_ACL */
729#if HAVE_DARWIN_ACL
730	acl_entry_t aclent;
731	acl_permset_t permset;
732	const uid_t uid = 1000;
733	uuid_t uuid;
734#endif	/* HAVE_DARWIN_ACL */
735	acl_t acl;
736#endif	/* !HAVE_SUN_ACL */
737
738	/*
739	 * First, do a quick manual set/read of ACL data to
740	 * verify that the local filesystem does support ACLs.
741	 * If it doesn't, we'll simply skip the remaining tests.
742	 */
743#if HAVE_POSIX_ACL && HAVE_ACL_TYPE_NFS4
744	acl = acl_from_text("owner@:rwxp::allow,group@:rwp:f:allow");
745	failure("acl_from_text(): errno = %d (%s)", errno, strerror(errno));
746	assert((void *)acl != NULL);
747#elif HAVE_DARWIN_ACL
748	acl = acl_init(1);
749	assert((void *)acl != NULL);
750	assertEqualInt(0, acl_create_entry(&acl, &aclent));
751	assertEqualInt(0, acl_set_tag_type(aclent, ACL_EXTENDED_ALLOW));
752	assertEqualInt(0, acl_get_permset(aclent, &permset));
753	assertEqualInt(0, acl_add_perm(permset, ACL_READ_DATA));
754	assertEqualInt(0, acl_add_perm(permset, ACL_WRITE_DATA));
755	assertEqualInt(0, acl_add_perm(permset, ACL_APPEND_DATA));
756	assertEqualInt(0, acl_add_perm(permset, ACL_EXECUTE));
757	assertEqualInt(0, acl_set_permset(aclent, permset));
758	assertEqualInt(0, mbr_identifier_to_uuid(ID_TYPE_UID, &uid,
759	    sizeof(uid_t), uuid));
760	assertEqualInt(0, acl_set_qualifier(aclent, uuid));
761#endif
762
763	/* Create a test dir and try to set an ACL on it. */
764	if (!assertMakeDir("pretest", 0755)) {
765#if !HAVE_SUN_ACL
766		acl_free(acl);
767#endif
768		return;
769	}
770
771#if HAVE_SUN_ACL
772	func = "acl_get()";
773	n = acl_get("pretest", 0, &acl);
774#else
775	func = "acl_set_file()";
776#if HAVE_DARWIN_ACL
777	n = acl_set_file("pretest", ACL_TYPE_EXTENDED, acl);
778#else
779	n = acl_set_file("pretest", ACL_TYPE_NFS4, acl);
780#endif
781	acl_free(acl);
782#endif
783	if (n != 0) {
784#if HAVE_SUN_ACL
785		if (errno == ENOSYS)
786#else
787		if (errno == EOPNOTSUPP || errno == EINVAL)
788#endif
789		{
790			skipping("NFS4 ACL is not supported on this filesystem");
791			return;
792		}
793	}
794	failure("%s: errno = %d (%s)", func, errno, strerror(errno));
795	assertEqualInt(0, n);
796
797#if HAVE_SUN_ACL
798	if (acl->acl_type != ACE_T) {
799		acl_free(acl);
800		skipping("NFS4 ACL is not supported on this filesystem");
801		return;
802	}
803	acl_free(acl);
804#endif
805
806	/* Create a write-to-disk object. */
807	assert(NULL != (a = archive_write_disk_new()));
808	archive_write_disk_set_options(a,
809	    ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_ACL);
810
811	/* Populate an archive entry with some metadata, including ACL info */
812	ae = archive_entry_new();
813	assert(ae != NULL);
814	archive_entry_set_pathname(ae, "testall");
815	archive_entry_set_filetype(ae, AE_IFREG);
816	archive_entry_set_perm(ae, 0654);
817	archive_entry_set_mtime(ae, 123456, 7890);
818	archive_entry_set_size(ae, 0);
819	set_acls(ae, acls_reg, 0, acls_reg_cnt);
820
821	/* Write the entry to disk, including ACLs. */
822	assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
823
824	/* Likewise for a dir. */
825	archive_entry_set_pathname(ae, "dirall");
826	archive_entry_set_filetype(ae, AE_IFDIR);
827	archive_entry_set_perm(ae, 0654);
828	archive_entry_set_mtime(ae, 123456, 7890);
829	set_acls(ae, acls_dir, 0, acls_dir_cnt);
830	assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
831
832	for (i = 0; i < acls_dir_cnt; ++i) {
833	  sprintf(buff, "dir%d", i);
834	  archive_entry_set_pathname(ae, buff);
835	  archive_entry_set_filetype(ae, AE_IFDIR);
836	  archive_entry_set_perm(ae, 0654);
837	  archive_entry_set_mtime(ae, 123456 + i, 7891 + i);
838	  set_acls(ae, acls_dir, i, i + 1);
839	  assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
840	}
841
842	archive_entry_free(ae);
843
844	/* Close the archive. */
845	assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
846	assertEqualInt(ARCHIVE_OK, archive_write_free(a));
847
848	/* Verify the data on disk. */
849	assertEqualInt(0, stat("testall", &st));
850	assertEqualInt(st.st_mtime, 123456);
851#if HAVE_SUN_ACL
852	n = acl_get("testall", 0, &acl);
853	failure("acl_get(): errno = %d (%s)", errno, strerror(errno));
854	assertEqualInt(0, n);
855#else
856#if HAVE_DARWIN_ACL
857	acl = acl_get_file("testall", ACL_TYPE_EXTENDED);
858#else
859	acl = acl_get_file("testall", ACL_TYPE_NFS4);
860#endif
861	failure("acl_get_file(): errno = %d (%s)", errno, strerror(errno));
862	assert(acl != (acl_t)NULL);
863#endif
864	compare_acls(acl, acls_reg, "testall", 0, regcnt);
865	acl_free(acl);
866
867	/* Verify single-permission dirs on disk. */
868	for (i = 0; i < dircnt; ++i) {
869		sprintf(buff, "dir%d", i);
870		assertEqualInt(0, stat(buff, &st));
871		assertEqualInt(st.st_mtime, 123456 + i);
872#if HAVE_SUN_ACL
873		n = acl_get(buff, 0, &acl);
874		failure("acl_get(): errno = %d (%s)", errno, strerror(errno));
875		assertEqualInt(0, n);
876#else
877#if HAVE_DARWIN_ACL
878		acl = acl_get_file(buff, ACL_TYPE_EXTENDED);
879#else
880		acl = acl_get_file(buff, ACL_TYPE_NFS4);
881#endif
882		failure("acl_get_file(): errno = %d (%s)", errno,
883		    strerror(errno));
884		assert(acl != (acl_t)NULL);
885#endif
886		compare_acls(acl, acls_dir, buff, i, i + 1);
887		acl_free(acl);
888	}
889
890	/* Verify "dirall" on disk. */
891	assertEqualInt(0, stat("dirall", &st));
892	assertEqualInt(st.st_mtime, 123456);
893#if HAVE_SUN_ACL
894	n = acl_get("dirall", 0, &acl);
895	failure("acl_get(): errno = %d (%s)", errno, strerror(errno));
896	assertEqualInt(0, n);
897#else
898#if HAVE_DARWIN_ACL
899	acl = acl_get_file("dirall", ACL_TYPE_EXTENDED);
900#else
901	acl = acl_get_file("dirall", ACL_TYPE_NFS4);
902#endif
903	failure("acl_get_file(): errno = %d (%s)", errno, strerror(errno));
904	assert(acl != (acl_t)NULL);
905#endif
906	compare_acls(acl, acls_dir, "dirall", 0, dircnt);
907	acl_free(acl);
908
909	/* Read and compare ACL via archive_read_disk */
910	a = archive_read_disk_new();
911	assert(a != NULL);
912	ae = archive_entry_new();
913	assert(ae != NULL);
914	archive_entry_set_pathname(ae, "testall");
915	assertEqualInt(ARCHIVE_OK,
916		       archive_read_disk_entry_from_file(a, ae, -1, NULL));
917	compare_entry_acls(ae, acls_reg, "testall", 0, acls_reg_cnt);
918	archive_entry_free(ae);
919	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
920
921	/* Read and compare ACL via archive_read_disk */
922	a = archive_read_disk_new();
923	assert(a != NULL);
924	ae = archive_entry_new();
925	assert(ae != NULL);
926	archive_entry_set_pathname(ae, "dirall");
927	assertEqualInt(ARCHIVE_OK,
928	archive_read_disk_entry_from_file(a, ae, -1, NULL));
929	compare_entry_acls(ae, acls_dir, "dirall", 0, acls_dir_cnt);
930	archive_entry_free(ae);
931	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
932#endif /* HAVE_NFS4_ACL */
933}
934