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 ARCHIVE_ACL_NFS4
30 #if HAVE_SYS_ACL_H
31 #define _ACL_PRIVATE
32 #include <sys/acl.h>
33 #endif
34 #if HAVE_SYS_RICHACL_H
35 #include <sys/richacl.h>
36 #endif
37 #if HAVE_MEMBERSHIP_H
38 #include <membership.h>
39 #endif
40 
41 struct myacl_t {
42 	int type;
43 	int permset;
44 	int tag;
45 	int qual; /* GID or UID of user/group, depending on tag. */
46 	const char *name; /* Name of user/group, depending on tag. */
47 };
48 
49 static struct myacl_t acls_reg[] = {
50 #if !ARCHIVE_ACL_DARWIN
51 	/* For this test, we need the file owner to be able to read and write the ACL. */
52 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
53 	  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,
54 	  ARCHIVE_ENTRY_ACL_USER_OBJ, -1, ""},
55 #endif
56 	/* An entry for each type. */
57 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE,
58 	  ARCHIVE_ENTRY_ACL_USER, 108, "user108" },
59 	{ ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_EXECUTE,
60 	  ARCHIVE_ENTRY_ACL_USER, 109, "user109" },
61 
62 	/* An entry for each permission. */
63 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE,
64 	  ARCHIVE_ENTRY_ACL_USER, 112, "user112" },
65 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_DATA,
66 	  ARCHIVE_ENTRY_ACL_USER, 113, "user113" },
67 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_DATA,
68 	  ARCHIVE_ENTRY_ACL_USER, 115, "user115" },
69 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_APPEND_DATA,
70 	  ARCHIVE_ENTRY_ACL_USER, 117, "user117" },
71 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS,
72 	  ARCHIVE_ENTRY_ACL_USER, 119, "user119" },
73 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS,
74 	  ARCHIVE_ENTRY_ACL_USER, 120, "user120" },
75 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES,
76 	  ARCHIVE_ENTRY_ACL_USER, 122, "user122" },
77 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES,
78 	  ARCHIVE_ENTRY_ACL_USER, 123, "user123" },
79 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_DELETE,
80 	  ARCHIVE_ENTRY_ACL_USER, 124, "user124" },
81 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_ACL,
82 	  ARCHIVE_ENTRY_ACL_USER, 125, "user125" },
83 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_ACL,
84 	  ARCHIVE_ENTRY_ACL_USER, 126, "user126" },
85 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_OWNER,
86 	  ARCHIVE_ENTRY_ACL_USER, 127, "user127" },
87 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_SYNCHRONIZE,
88 	  ARCHIVE_ENTRY_ACL_USER, 128, "user128" },
89 
90 	/* One entry for each qualifier. */
91 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE,
92 	  ARCHIVE_ENTRY_ACL_USER, 135, "user135" },
93 //	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE,
94 //	  ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" },
95 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE,
96 	  ARCHIVE_ENTRY_ACL_GROUP, 136, "group136" },
97 #if !ARCHIVE_ACL_DARWIN
98 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE,
99 	  ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" },
100 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE,
101 	  ARCHIVE_ENTRY_ACL_EVERYONE, -1, "" }
102 #else	/* MacOS - mode 0654 */
103 	{ ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_EXECUTE,
104 	  ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" },
105 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
106 	    ARCHIVE_ENTRY_ACL_READ_DATA |
107 	    ARCHIVE_ENTRY_ACL_WRITE_DATA |
108 	    ARCHIVE_ENTRY_ACL_APPEND_DATA |
109 	    ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES |
110 	    ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES |
111 	    ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS |
112 	    ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS |
113 	    ARCHIVE_ENTRY_ACL_READ_ACL |
114 	    ARCHIVE_ENTRY_ACL_WRITE_ACL |
115 	    ARCHIVE_ENTRY_ACL_WRITE_OWNER |
116 	    ARCHIVE_ENTRY_ACL_SYNCHRONIZE,
117 	  ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" },
118 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
119 	    ARCHIVE_ENTRY_ACL_READ_DATA |
120 	    ARCHIVE_ENTRY_ACL_EXECUTE |
121 	    ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES |
122 	    ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS |
123 	    ARCHIVE_ENTRY_ACL_READ_ACL |
124 	    ARCHIVE_ENTRY_ACL_SYNCHRONIZE,
125 	  ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" },
126 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
127 	    ARCHIVE_ENTRY_ACL_READ_DATA |
128 	    ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES |
129 	    ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS |
130 	    ARCHIVE_ENTRY_ACL_READ_ACL |
131 	    ARCHIVE_ENTRY_ACL_SYNCHRONIZE,
132 	  ARCHIVE_ENTRY_ACL_EVERYONE, -1, "" }
133 #endif
134 };
135 
136 static const int acls_reg_cnt = (int)(sizeof(acls_reg)/sizeof(acls_reg[0]));
137 
138 static struct myacl_t acls_dir[] = {
139 	/* For this test, we need to be able to read and write the ACL. */
140 #if !ARCHIVE_ACL_DARWIN
141 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_READ_ACL,
142 	  ARCHIVE_ENTRY_ACL_USER_OBJ, -1, ""},
143 #endif
144 
145 	/* An entry for each type. */
146 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY,
147 	  ARCHIVE_ENTRY_ACL_USER, 101, "user101" },
148 	{ ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY,
149 	  ARCHIVE_ENTRY_ACL_USER, 102, "user102" },
150 
151 	/* An entry for each permission. */
152 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY,
153 	  ARCHIVE_ENTRY_ACL_USER, 201, "user201" },
154 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_ADD_FILE,
155 	  ARCHIVE_ENTRY_ACL_USER, 202, "user202" },
156 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY,
157 	  ARCHIVE_ENTRY_ACL_USER, 203, "user203" },
158 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS,
159 	  ARCHIVE_ENTRY_ACL_USER, 204, "user204" },
160 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS,
161 	  ARCHIVE_ENTRY_ACL_USER, 205, "user205" },
162 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_DELETE_CHILD,
163 	  ARCHIVE_ENTRY_ACL_USER, 206, "user206" },
164 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES,
165 	  ARCHIVE_ENTRY_ACL_USER, 207, "user207" },
166 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES,
167 	  ARCHIVE_ENTRY_ACL_USER, 208, "user208" },
168 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_DELETE,
169 	  ARCHIVE_ENTRY_ACL_USER, 209, "user209" },
170 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_ACL,
171 	  ARCHIVE_ENTRY_ACL_USER, 210, "user210" },
172 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_ACL,
173 	  ARCHIVE_ENTRY_ACL_USER, 211, "user211" },
174 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_OWNER,
175 	  ARCHIVE_ENTRY_ACL_USER, 212, "user212" },
176 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_SYNCHRONIZE,
177 	  ARCHIVE_ENTRY_ACL_USER, 213, "user213" },
178 
179 	/* One entry with each inheritance value. */
180 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
181 	  ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT,
182 	  ARCHIVE_ENTRY_ACL_USER, 301, "user301" },
183 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
184 	  ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT,
185 	  ARCHIVE_ENTRY_ACL_USER, 302, "user302" },
186 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
187 	  ARCHIVE_ENTRY_ACL_READ_DATA |
188 	  ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT |
189 	  ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT,
190 	  ARCHIVE_ENTRY_ACL_USER, 303, "user303" },
191 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
192 	  ARCHIVE_ENTRY_ACL_READ_DATA |
193 	  ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT |
194 	  ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY,
195 	  ARCHIVE_ENTRY_ACL_USER, 304, "user304" },
196 #if !defined(ARCHIVE_ACL_SUNOS_NFS4) || defined(ACE_INHERITED_ACE)
197 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
198 	  ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_INHERITED,
199 	  ARCHIVE_ENTRY_ACL_USER, 305, "user305" },
200 #endif
201 
202 #if 0
203 	/* FreeBSD does not support audit entries. */
204 	{ ARCHIVE_ENTRY_ACL_TYPE_AUDIT,
205 	  ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS,
206 	  ARCHIVE_ENTRY_ACL_USER, 401, "user401" },
207 	{ ARCHIVE_ENTRY_ACL_TYPE_AUDIT,
208 	  ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS,
209 	  ARCHIVE_ENTRY_ACL_USER, 402, "user402" },
210 #endif
211 
212 	/* One entry for each qualifier. */
213 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY,
214 	  ARCHIVE_ENTRY_ACL_USER, 501, "user501" },
215 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY,
216 	  ARCHIVE_ENTRY_ACL_GROUP, 502, "group502" },
217 #if !ARCHIVE_ACL_DARWIN
218 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY,
219 	  ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" },
220 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY,
221 	  ARCHIVE_ENTRY_ACL_EVERYONE, -1, "" }
222 #else	/* MacOS - mode 0654 */
223 	{ ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_EXECUTE,
224 	  ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" },
225 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
226 	    ARCHIVE_ENTRY_ACL_READ_DATA |
227 	    ARCHIVE_ENTRY_ACL_WRITE_DATA |
228 	    ARCHIVE_ENTRY_ACL_APPEND_DATA |
229 	    ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES |
230 	    ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES |
231 	    ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS |
232 	    ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS |
233 	    ARCHIVE_ENTRY_ACL_READ_ACL |
234 	    ARCHIVE_ENTRY_ACL_WRITE_ACL |
235 	    ARCHIVE_ENTRY_ACL_WRITE_OWNER |
236 	    ARCHIVE_ENTRY_ACL_SYNCHRONIZE,
237 	  ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" },
238 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
239 	    ARCHIVE_ENTRY_ACL_READ_DATA |
240 	    ARCHIVE_ENTRY_ACL_EXECUTE |
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_GROUP_OBJ, -1, "" },
246 	{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
247 	    ARCHIVE_ENTRY_ACL_READ_DATA |
248 	    ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES |
249 	    ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS |
250 	    ARCHIVE_ENTRY_ACL_READ_ACL |
251 	    ARCHIVE_ENTRY_ACL_SYNCHRONIZE,
252 	  ARCHIVE_ENTRY_ACL_EVERYONE, -1, "" }
253 #endif
254 };
255 
256 static const int acls_dir_cnt = (int)(sizeof(acls_dir)/sizeof(acls_dir[0]));
257 
258 static void
259 set_acls(struct archive_entry *ae, struct myacl_t *acls, int start, int end)
260 {
261 	int i;
262 
263 	archive_entry_acl_clear(ae);
264 #if !ARCHIVE_ACL_DARWIN
265 	if (start > 0) {
266 		assertEqualInt(ARCHIVE_OK,
267 			archive_entry_acl_add_entry(ae,
268 			    acls[0].type, acls[0].permset, acls[0].tag,
269 			    acls[0].qual, acls[0].name));
270 	}
271 #endif
272 	for (i = start; i < end; i++) {
273 		assertEqualInt(ARCHIVE_OK,
274 		    archive_entry_acl_add_entry(ae,
275 			acls[i].type, acls[i].permset, acls[i].tag,
276 			acls[i].qual, acls[i].name));
277 	}
278 }
279 
280 static int
281 #if ARCHIVE_ACL_SUNOS_NFS4
282 acl_permset_to_bitmap(uint32_t mask)
283 #elif ARCHIVE_ACL_LIBRICHACL
284 acl_permset_to_bitmap(unsigned int mask)
285 #else
286 acl_permset_to_bitmap(acl_permset_t opaque_ps)
287 #endif
288 {
289 	static struct { int portable; int machine; } perms[] = {
290 #ifdef ARCHIVE_ACL_SUNOS_NFS4	/* Solaris NFSv4 ACL permissions */
291 		{ARCHIVE_ENTRY_ACL_EXECUTE, ACE_EXECUTE},
292 		{ARCHIVE_ENTRY_ACL_READ_DATA, ACE_READ_DATA},
293 		{ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACE_LIST_DIRECTORY},
294 		{ARCHIVE_ENTRY_ACL_WRITE_DATA, ACE_WRITE_DATA},
295 		{ARCHIVE_ENTRY_ACL_ADD_FILE, ACE_ADD_FILE},
296 		{ARCHIVE_ENTRY_ACL_APPEND_DATA, ACE_APPEND_DATA},
297 		{ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACE_ADD_SUBDIRECTORY},
298 		{ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACE_READ_NAMED_ATTRS},
299 		{ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACE_WRITE_NAMED_ATTRS},
300 		{ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACE_DELETE_CHILD},
301 		{ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACE_READ_ATTRIBUTES},
302 		{ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACE_WRITE_ATTRIBUTES},
303 		{ARCHIVE_ENTRY_ACL_DELETE, ACE_DELETE},
304 		{ARCHIVE_ENTRY_ACL_READ_ACL, ACE_READ_ACL},
305 		{ARCHIVE_ENTRY_ACL_WRITE_ACL, ACE_WRITE_ACL},
306 		{ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACE_WRITE_OWNER},
307 		{ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACE_SYNCHRONIZE}
308 #elif ARCHIVE_ACL_DARWIN	/* MacOS NFSv4 ACL permissions */
309 		{ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA},
310 		{ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY},
311 		{ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA},
312 		{ARCHIVE_ENTRY_ACL_ADD_FILE, ACL_ADD_FILE},
313 		{ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE},
314 		{ARCHIVE_ENTRY_ACL_DELETE, ACL_DELETE},
315 		{ARCHIVE_ENTRY_ACL_APPEND_DATA, ACL_APPEND_DATA},
316 		{ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACL_ADD_SUBDIRECTORY},
317 		{ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACL_DELETE_CHILD},
318 		{ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES},
319 		{ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES},
320 		{ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACL_READ_EXTATTRIBUTES},
321 		{ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACL_WRITE_EXTATTRIBUTES},
322 		{ARCHIVE_ENTRY_ACL_READ_ACL, ACL_READ_SECURITY},
323 		{ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_SECURITY},
324 		{ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_CHANGE_OWNER},
325 #if HAVE_DECL_ACL_SYNCHRONIZE
326 		{ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE}
327 #endif
328 #elif ARCHIVE_ACL_LIBRICHACL
329 		{ARCHIVE_ENTRY_ACL_EXECUTE, RICHACE_EXECUTE},
330 		{ARCHIVE_ENTRY_ACL_READ_DATA, RICHACE_READ_DATA},
331 		{ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, RICHACE_LIST_DIRECTORY},
332 		{ARCHIVE_ENTRY_ACL_WRITE_DATA, RICHACE_WRITE_DATA},
333 		{ARCHIVE_ENTRY_ACL_ADD_FILE, RICHACE_ADD_FILE},
334 		{ARCHIVE_ENTRY_ACL_APPEND_DATA, RICHACE_APPEND_DATA},
335 		{ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, RICHACE_ADD_SUBDIRECTORY},
336 		{ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, RICHACE_READ_NAMED_ATTRS},
337 		{ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, RICHACE_WRITE_NAMED_ATTRS},
338 		{ARCHIVE_ENTRY_ACL_DELETE_CHILD, RICHACE_DELETE_CHILD},
339 		{ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, RICHACE_READ_ATTRIBUTES},
340 		{ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, RICHACE_WRITE_ATTRIBUTES},
341 		{ARCHIVE_ENTRY_ACL_DELETE, RICHACE_DELETE},
342 		{ARCHIVE_ENTRY_ACL_READ_ACL, RICHACE_READ_ACL},
343 		{ARCHIVE_ENTRY_ACL_WRITE_ACL, RICHACE_WRITE_ACL},
344 		{ARCHIVE_ENTRY_ACL_WRITE_OWNER, RICHACE_WRITE_OWNER},
345 		{ARCHIVE_ENTRY_ACL_SYNCHRONIZE, RICHACE_SYNCHRONIZE}
346 #else	/* FreeBSD NFSv4 ACL permissions */
347 		{ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE},
348 		{ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA},
349 		{ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY},
350 		{ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA},
351 		{ARCHIVE_ENTRY_ACL_ADD_FILE, ACL_ADD_FILE},
352 		{ARCHIVE_ENTRY_ACL_APPEND_DATA, ACL_APPEND_DATA},
353 		{ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACL_ADD_SUBDIRECTORY},
354 		{ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACL_READ_NAMED_ATTRS},
355 		{ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACL_WRITE_NAMED_ATTRS},
356 		{ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACL_DELETE_CHILD},
357 		{ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES},
358 		{ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES},
359 		{ARCHIVE_ENTRY_ACL_DELETE, ACL_DELETE},
360 		{ARCHIVE_ENTRY_ACL_READ_ACL, ACL_READ_ACL},
361 		{ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_ACL},
362 		{ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_WRITE_OWNER},
363 		{ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE}
364 #endif
365 	};
366 	int i, permset = 0;
367 
368 	for (i = 0; i < (int)(sizeof(perms)/sizeof(perms[0])); ++i)
369 #if ARCHIVE_ACL_SUNOS_NFS4 || ARCHIVE_ACL_LIBRICHACL
370 		if (mask & perms[i].machine)
371 #else
372 		if (acl_get_perm_np(opaque_ps, perms[i].machine))
373 #endif
374 			permset |= perms[i].portable;
375 	return permset;
376 }
377 
378 static int
379 #if ARCHIVE_ACL_SUNOS_NFS4
380 acl_flagset_to_bitmap(uint16_t flags)
381 #elif ARCHIVE_ACL_LIBRICHACL
382 acl_flagset_to_bitmap(int flags)
383 #else
384 acl_flagset_to_bitmap(acl_flagset_t opaque_fs)
385 #endif
386 {
387 	static struct { int portable; int machine; } perms[] = {
388 #if ARCHIVE_ACL_SUNOS_NFS4	/* Solaris NFSv4 ACL inheritance flags */
389 		{ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACE_FILE_INHERIT_ACE},
390 		{ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACE_DIRECTORY_INHERIT_ACE},
391 		{ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACE_NO_PROPAGATE_INHERIT_ACE},
392 		{ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACE_INHERIT_ONLY_ACE},
393 		{ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, ACE_SUCCESSFUL_ACCESS_ACE_FLAG},
394 		{ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, ACE_FAILED_ACCESS_ACE_FLAG},
395 #ifdef ACE_INHERITED_ACE
396 		{ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACE_INHERITED_ACE}
397 #endif
398 #elif ARCHIVE_ACL_DARWIN	/* MacOS NFSv4 ACL inheritance flags */
399 		{ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACL_ENTRY_INHERITED},
400 		{ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT},
401 		{ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT},
402 		{ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_LIMIT_INHERIT},
403 		{ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_ONLY_INHERIT}
404 #elif ARCHIVE_ACL_LIBRICHACL
405 		{ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, RICHACE_FILE_INHERIT_ACE},
406 		{ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, RICHACE_DIRECTORY_INHERIT_ACE},
407 		{ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, RICHACE_NO_PROPAGATE_INHERIT_ACE},
408 		{ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, RICHACE_INHERIT_ONLY_ACE},
409 		{ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, RICHACE_INHERITED_ACE}
410 #else	/* FreeBSD NFSv4 ACL inheritance flags */
411 #ifdef ACL_ENTRY_INHERITED
412 		{ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACL_ENTRY_INHERITED},
413 #endif
414 		{ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT},
415 		{ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT},
416 		{ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_NO_PROPAGATE_INHERIT},
417 		{ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, ACL_ENTRY_SUCCESSFUL_ACCESS},
418 		{ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, ACL_ENTRY_FAILED_ACCESS},
419 		{ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_INHERIT_ONLY}
420 #endif
421 	};
422 	int i, flagset = 0;
423 
424 	for (i = 0; i < (int)(sizeof(perms)/sizeof(perms[0])); ++i)
425 #if ARCHIVE_ACL_SUNOS_NFS4 || ARCHIVE_ACL_LIBRICHACL
426 		if (flags & perms[i].machine)
427 #else
428 		if (acl_get_flag_np(opaque_fs, perms[i].machine))
429 #endif
430 			flagset |= perms[i].portable;
431 	return flagset;
432 }
433 
434 #if ARCHIVE_ACL_SUNOS_NFS4
435 static int
436 acl_match(ace_t *ace, struct myacl_t *myacl)
437 {
438 	int perms;
439 
440 	perms = acl_permset_to_bitmap(ace->a_access_mask) | acl_flagset_to_bitmap(ace->a_flags);
441 
442 	if (perms != myacl->permset)
443 		return (0);
444 
445 	switch (ace->a_type) {
446 	case ACE_ACCESS_ALLOWED_ACE_TYPE:
447 		if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_ALLOW)
448 			return (0);
449 		break;
450 	case ACE_ACCESS_DENIED_ACE_TYPE:
451 		if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_DENY)
452 			return (0);
453 		break;
454 	case ACE_SYSTEM_AUDIT_ACE_TYPE:
455 		if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_AUDIT)
456 			return (0);
457 		break;
458 	case ACE_SYSTEM_ALARM_ACE_TYPE:
459 		if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_ALARM)
460 			return (0);
461 		break;
462 	default:
463 		return (0);
464 	}
465 
466 	if (ace->a_flags & ACE_OWNER) {
467 		if (myacl->tag != ARCHIVE_ENTRY_ACL_USER_OBJ)
468 			return (0);
469 	} else if (ace->a_flags & ACE_GROUP) {
470 		if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP_OBJ)
471 			return (0);
472 	} else if (ace->a_flags & ACE_EVERYONE) {
473 		if (myacl->tag != ARCHIVE_ENTRY_ACL_EVERYONE)
474 			return (0);
475 	} else if (ace->a_flags & ACE_IDENTIFIER_GROUP) {
476 		if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP)
477 			return (0);
478 		if ((gid_t)myacl->qual != ace->a_who)
479 			return (0);
480 	} else {
481 		if (myacl->tag != ARCHIVE_ENTRY_ACL_USER)
482 			return (0);
483 		if ((uid_t)myacl->qual != ace->a_who)
484 			return (0);
485 	}
486 	return (1);
487 }
488 #elif ARCHIVE_ACL_LIBRICHACL
489 static int
490 acl_match(struct richace *richace, struct myacl_t *myacl)
491 {
492 	int perms;
493 
494 	perms = acl_permset_to_bitmap(richace->e_mask) |
495 	    acl_flagset_to_bitmap(richace->e_flags);
496 
497 	if (perms != myacl->permset)
498 		return (0);
499 
500 	switch (richace->e_type) {
501 	case RICHACE_ACCESS_ALLOWED_ACE_TYPE:
502 		if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_ALLOW)
503 			return (0);
504 		break;
505 	case RICHACE_ACCESS_DENIED_ACE_TYPE:
506 		if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_DENY)
507 			return (0);
508 		break;
509 	default:
510 		return (0);
511 	}
512 
513 	if (richace->e_flags & RICHACE_SPECIAL_WHO) {
514 		switch (richace->e_id) {
515 		case RICHACE_OWNER_SPECIAL_ID:
516 			if (myacl->tag != ARCHIVE_ENTRY_ACL_USER_OBJ)
517 				return (0);
518 			break;
519 		case RICHACE_GROUP_SPECIAL_ID:
520 			if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP_OBJ)
521 				return (0);
522 			break;
523 		case RICHACE_EVERYONE_SPECIAL_ID:
524 			if (myacl->tag != ARCHIVE_ENTRY_ACL_EVERYONE)
525 				return (0);
526 			break;
527 		default:
528 			/* Invalid e_id */
529 			return (0);
530 		}
531 	} else if (richace->e_flags & RICHACE_IDENTIFIER_GROUP) {
532 		if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP)
533 			return (0);
534 		if ((gid_t)myacl->qual != richace->e_id)
535 			return (0);
536 	} else {
537 		if (myacl->tag != ARCHIVE_ENTRY_ACL_USER)
538 			return (0);
539 		if ((uid_t)myacl->qual != richace->e_id)
540 			return (0);
541 	}
542 	return (1);
543 }
544 #elif ARCHIVE_ACL_DARWIN
545 static int
546 acl_match(acl_entry_t aclent, struct myacl_t *myacl)
547 {
548 	void *q;
549 	uid_t ugid;
550 	int r, idtype;
551 	acl_tag_t tag_type;
552 	acl_permset_t opaque_ps;
553 	acl_flagset_t opaque_fs;
554 	int perms;
555 
556 	acl_get_tag_type(aclent, &tag_type);
557 
558 	/* translate the silly opaque permset to a bitmap */
559 	acl_get_permset(aclent, &opaque_ps);
560 	acl_get_flagset_np(aclent, &opaque_fs);
561 	perms = acl_permset_to_bitmap(opaque_ps) | acl_flagset_to_bitmap(opaque_fs);
562 	if (perms != myacl->permset)
563 		return (0);
564 
565 	r = 0;
566 	switch (tag_type) {
567 	case ACL_EXTENDED_ALLOW:
568 		if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_ALLOW)
569 			return (0);
570 		break;
571 	case ACL_EXTENDED_DENY:
572 		if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_DENY)
573 			return (0);
574 		break;
575 	default:
576 		return (0);
577 	}
578 	q = acl_get_qualifier(aclent);
579 	if (q == NULL)
580 		return (0);
581 	r = mbr_uuid_to_id((const unsigned char *)q, &ugid, &idtype);
582 	acl_free(q);
583 	if (r != 0)
584 		return (0);
585 	switch (idtype) {
586 		case ID_TYPE_UID:
587 			if (myacl->tag != ARCHIVE_ENTRY_ACL_USER)
588 				return (0);
589 			if ((uid_t)myacl->qual != ugid)
590 				return (0);
591 			break;
592 		case ID_TYPE_GID:
593 			if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP)
594 				return (0);
595 			if ((gid_t)myacl->qual != ugid)
596 				return (0);
597 			break;
598 		default:
599 			return (0);
600 	}
601 	return (1);
602 }
603 #else /* ARCHIVE_ACL_FREEBSD_NFS4 */
604 static int
605 acl_match(acl_entry_t aclent, struct myacl_t *myacl)
606 {
607 	gid_t g, *gp;
608 	uid_t u, *up;
609 	acl_entry_type_t entry_type;
610 	acl_tag_t tag_type;
611 	acl_permset_t opaque_ps;
612 	acl_flagset_t opaque_fs;
613 	int perms;
614 
615 	acl_get_tag_type(aclent, &tag_type);
616 	acl_get_entry_type_np(aclent, &entry_type);
617 
618 	/* translate the silly opaque permset to a bitmap */
619 	acl_get_permset(aclent, &opaque_ps);
620 	acl_get_flagset_np(aclent, &opaque_fs);
621 	perms = acl_permset_to_bitmap(opaque_ps) | acl_flagset_to_bitmap(opaque_fs);
622 	if (perms != myacl->permset)
623 		return (0);
624 
625 	switch (entry_type) {
626 	case ACL_ENTRY_TYPE_ALLOW:
627 		if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_ALLOW)
628 			return (0);
629 		break;
630 	case ACL_ENTRY_TYPE_DENY:
631 		if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_DENY)
632 			return (0);
633 		break;
634 	case ACL_ENTRY_TYPE_AUDIT:
635 		if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_AUDIT)
636 			return (0);
637 		break;
638 	case ACL_ENTRY_TYPE_ALARM:
639 		if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_ALARM)
640 			return (0);
641 		break;
642 	default:
643 		return (0);
644 	}
645 
646 	switch (tag_type) {
647 	case ACL_USER_OBJ:
648 		if (myacl->tag != ARCHIVE_ENTRY_ACL_USER_OBJ) return (0);
649 		break;
650 	case ACL_USER:
651 		if (myacl->tag != ARCHIVE_ENTRY_ACL_USER)
652 			return (0);
653 		up = acl_get_qualifier(aclent);
654 		u = *up;
655 		acl_free(up);
656 		if ((uid_t)myacl->qual != u)
657 			return (0);
658 		break;
659 	case ACL_GROUP_OBJ:
660 		if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP_OBJ) return (0);
661 		break;
662 	case ACL_GROUP:
663 		if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP)
664 			return (0);
665 		gp = acl_get_qualifier(aclent);
666 		g = *gp;
667 		acl_free(gp);
668 		if ((gid_t)myacl->qual != g)
669 			return (0);
670 		break;
671 	case ACL_MASK:
672 		if (myacl->tag != ARCHIVE_ENTRY_ACL_MASK) return (0);
673 		break;
674 	case ACL_EVERYONE:
675 		if (myacl->tag != ARCHIVE_ENTRY_ACL_EVERYONE) return (0);
676 		break;
677 	}
678 	return (1);
679 }
680 #endif	/* various ARCHIVE_ACL_NFS4 implementations */
681 
682 static void
683 compare_acls(
684 #if ARCHIVE_ACL_SUNOS_NFS4
685     void *aclp,
686     int aclcnt,
687 #elif ARCHIVE_ACL_LIBRICHACL
688     struct richacl *richacl,
689 #else
690     acl_t acl,
691 #endif
692     struct myacl_t *myacls, const char *filename, int start, int end)
693 {
694 	int *marker;
695 	int matched;
696 	int i, n;
697 #if ARCHIVE_ACL_SUNOS_NFS4
698 	int e;
699 	ace_t *acl_entry;
700 #elif ARCHIVE_ACL_LIBRICHACL
701 	int e;
702 	struct richace *acl_entry;
703 	int aclcnt;
704 #else
705 	int entry_id = ACL_FIRST_ENTRY;
706 	acl_entry_t acl_entry;
707 #if ARCHIVE_ACL_DARWIN
708 	const int acl_get_entry_ret = 0;
709 #else
710 	const int acl_get_entry_ret = 1;
711 #endif
712 #endif
713 
714 #if ARCHIVE_ACL_SUNOS_NFS4
715 	if (aclp == NULL)
716 		return;
717 #elif ARCHIVE_ACL_LIBRICHACL
718 	if (richacl == NULL)
719 		return;
720 	aclcnt = richacl->a_count;
721 #else
722 	if (acl == NULL)
723 		return;
724 #endif
725 
726 	n = end - start;
727 	marker = malloc(sizeof(marker[0]) * (n + 1));
728 	for (i = 0; i < n; i++)
729 		marker[i] = i + start;
730 #if !ARCHIVE_ACL_DARWIN
731 	/* Always include the first ACE. */
732 	if (start > 0) {
733 	  marker[n] = 0;
734 	  ++n;
735 	}
736 #endif
737 
738 	/*
739 	 * Iterate over acls in system acl object, try to match each
740 	 * one with an item in the myacls array.
741 	 */
742 #if ARCHIVE_ACL_SUNOS_NFS4 || ARCHIVE_ACL_LIBRICHACL
743 	for (e = 0; e < aclcnt; e++)
744 #else
745 	while (acl_get_entry_ret == acl_get_entry(acl, entry_id, &acl_entry))
746 #endif
747 	{
748 #if ARCHIVE_ACL_SUNOS_NFS4
749 		acl_entry = &((ace_t *)aclp)[e];
750 #elif ARCHIVE_ACL_LIBRICHACL
751 		acl_entry = &(richacl->a_entries[e]);
752 #else
753 		/* After the first time... */
754 		entry_id = ACL_NEXT_ENTRY;
755 #endif
756 		/* Search for a matching entry (tag and qualifier) */
757 		for (i = 0, matched = 0; i < n && !matched; i++) {
758 			if (acl_match(acl_entry, &myacls[marker[i]])) {
759 				/* We found a match; remove it. */
760 				marker[i] = marker[n - 1];
761 				n--;
762 				matched = 1;
763 			}
764 		}
765 
766 		failure("ACL entry on file %s that shouldn't be there",
767 		    filename);
768 		assert(matched == 1);
769 	}
770 
771 	/* Dump entries in the myacls array that weren't in the system acl. */
772 	for (i = 0; i < n; ++i) {
773 		failure(" ACL entry %d missing from %s: "
774 		    "type=%#010x,permset=%#010x,tag=%d,qual=%d,name=``%s''\n",
775 		    marker[i], filename,
776 		    myacls[marker[i]].type, myacls[marker[i]].permset,
777 		    myacls[marker[i]].tag, myacls[marker[i]].qual,
778 		    myacls[marker[i]].name);
779 		assert(0); /* Record this as a failure. */
780 	}
781 	free(marker);
782 }
783 
784 static void
785 compare_entry_acls(struct archive_entry *ae, struct myacl_t *myacls, const char *filename, int start, int end)
786 {
787 	int *marker;
788 	int matched;
789 	int i, n;
790 	int type, permset, tag, qual;
791 	const char *name;
792 
793 	/* Count ACL entries in myacls array and allocate an indirect array. */
794 	n = end - start;
795 	marker = malloc(sizeof(marker[0]) * (n + 1));
796 	for (i = 0; i < n; i++)
797 		marker[i] = i + start;
798 	/* Always include the first ACE. */
799 	if (start > 0) {
800 	  marker[n] = 0;
801 	  ++n;
802 	}
803 
804 	/*
805 	 * Iterate over acls in entry, try to match each
806 	 * one with an item in the myacls array.
807 	 */
808 	assertEqualInt(n, archive_entry_acl_reset(ae,
809 	    ARCHIVE_ENTRY_ACL_TYPE_NFS4));
810 	while (ARCHIVE_OK == archive_entry_acl_next(ae,
811 	    ARCHIVE_ENTRY_ACL_TYPE_NFS4, &type, &permset, &tag, &qual, &name)) {
812 
813 		/* Search for a matching entry (tag and qualifier) */
814 		for (i = 0, matched = 0; i < n && !matched; i++) {
815 			if (tag == myacls[marker[i]].tag
816 			    && qual == myacls[marker[i]].qual
817 			    && permset == myacls[marker[i]].permset
818 			    && type == myacls[marker[i]].type) {
819 				/* We found a match; remove it. */
820 				marker[i] = marker[n - 1];
821 				n--;
822 				matched = 1;
823 			}
824 		}
825 
826 		failure("ACL entry on file that shouldn't be there: "
827 			"type=%#010x,permset=%#010x,tag=%d,qual=%d",
828 			type,permset,tag,qual);
829 		assert(matched == 1);
830 	}
831 
832 	/* Dump entries in the myacls array that weren't in the system acl. */
833 	for (i = 0; i < n; ++i) {
834 		failure(" ACL entry %d missing from %s: "
835 		    "type=%#010x,permset=%#010x,tag=%d,qual=%d,name=``%s''\n",
836 		    marker[i], filename,
837 		    myacls[marker[i]].type, myacls[marker[i]].permset,
838 		    myacls[marker[i]].tag, myacls[marker[i]].qual,
839 		    myacls[marker[i]].name);
840 		assert(0); /* Record this as a failure. */
841 	}
842 	free(marker);
843 }
844 #endif	/* ARCHIVE_ACL_NFS4 */
845 
846 /*
847  * Verify ACL restore-to-disk.  This test is Platform-specific.
848  */
849 
850 DEFINE_TEST(test_acl_platform_nfs4)
851 {
852 #if !ARCHIVE_ACL_NFS4
853 	skipping("NFS4 ACLs are not supported on this platform");
854 #else /* ARCHIVE_ACL_NFS4 */
855 	char buff[64];
856 	int i;
857 	struct stat st;
858 	struct archive *a;
859 	struct archive_entry *ae;
860 #if ARCHIVE_ACL_DARWIN /* On MacOS we skip trivial ACLs in some tests */
861 	const int regcnt = acls_reg_cnt - 4;
862 	const int dircnt = acls_dir_cnt - 4;
863 #else
864 	const int regcnt = acls_reg_cnt;
865 	const int dircnt = acls_dir_cnt;
866 #endif
867 #if ARCHIVE_ACL_SUNOS_NFS4
868 	void *aclp;
869 	int aclcnt;
870 #elif ARCHIVE_ACL_LIBRICHACL
871 	struct richacl *richacl;
872 #else	/* !ARCHIVE_ACL_SUNOS_NFS4 */
873 	acl_t acl;
874 #endif
875 
876 	assertMakeFile("pretest", 0644, "a");
877 
878 	if (setTestAcl("pretest") != ARCHIVE_TEST_ACL_TYPE_NFS4) {
879 		skipping("NFS4 ACLs are not writable on this filesystem");
880 		return;
881 	}
882 
883 	/* Create a write-to-disk object. */
884 	assert(NULL != (a = archive_write_disk_new()));
885 	archive_write_disk_set_options(a,
886 	    ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_ACL);
887 
888 	/* Populate an archive entry with some metadata, including ACL info */
889 	ae = archive_entry_new();
890 	assert(ae != NULL);
891 	archive_entry_set_pathname(ae, "testall");
892 	archive_entry_set_filetype(ae, AE_IFREG);
893 	archive_entry_set_perm(ae, 0654);
894 	archive_entry_set_mtime(ae, 123456, 7890);
895 	archive_entry_set_size(ae, 0);
896 	set_acls(ae, acls_reg, 0, acls_reg_cnt);
897 
898 	/* Write the entry to disk, including ACLs. */
899 	assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
900 
901 	/* Likewise for a dir. */
902 	archive_entry_set_pathname(ae, "dirall");
903 	archive_entry_set_filetype(ae, AE_IFDIR);
904 	archive_entry_set_perm(ae, 0654);
905 	archive_entry_set_mtime(ae, 123456, 7890);
906 	set_acls(ae, acls_dir, 0, acls_dir_cnt);
907 	assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
908 
909 	for (i = 0; i < acls_dir_cnt; ++i) {
910 	  snprintf(buff, sizeof(buff), "dir%d", i);
911 	  archive_entry_set_pathname(ae, buff);
912 	  archive_entry_set_filetype(ae, AE_IFDIR);
913 	  archive_entry_set_perm(ae, 0654);
914 	  archive_entry_set_mtime(ae, 123456 + i, 7891 + i);
915 	  set_acls(ae, acls_dir, i, i + 1);
916 	  assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
917 	}
918 
919 	archive_entry_free(ae);
920 
921 	/* Close the archive. */
922 	assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
923 	assertEqualInt(ARCHIVE_OK, archive_write_free(a));
924 
925 	/* Verify the data on disk. */
926 	assertEqualInt(0, stat("testall", &st));
927 	assertEqualInt(st.st_mtime, 123456);
928 #if ARCHIVE_ACL_SUNOS_NFS4
929 	aclp = sunacl_get(ACE_GETACL, &aclcnt, 0, "testall");
930 	failure("acl(\"%s\"): errno = %d (%s)", "testall", errno,
931 	    strerror(errno));
932 	assert(aclp != NULL);
933 #elif ARCHIVE_ACL_LIBRICHACL
934 	richacl = richacl_get_file("testall");
935 	failure("richacl_get_file(\"%s\"): errno = %d (%s)", "testall", errno,
936 	    strerror(errno));
937 	assert(richacl != NULL);
938 #else
939 #if ARCHIVE_ACL_DARWIN
940 	acl = acl_get_file("testall", ACL_TYPE_EXTENDED);
941 #else
942 	acl = acl_get_file("testall", ACL_TYPE_NFS4);
943 #endif
944 	failure("acl_get_file(\"%s\"): errno = %d (%s)", "testall", errno,
945 	    strerror(errno));
946 	assert(acl != (acl_t)NULL);
947 #endif
948 #if ARCHIVE_ACL_SUNOS_NFS4
949 	compare_acls(aclp, aclcnt, acls_reg, "testall", 0, regcnt);
950 	free(aclp);
951 	aclp = NULL;
952 #elif ARCHIVE_ACL_LIBRICHACL
953 	compare_acls(richacl, acls_reg, "testall", 0, regcnt);
954 	richacl_free(richacl);
955 #else
956 	compare_acls(acl, acls_reg, "testall", 0, regcnt);
957 	acl_free(acl);
958 #endif
959 
960 
961 	/* Verify single-permission dirs on disk. */
962 	for (i = 0; i < dircnt; ++i) {
963 		snprintf(buff, sizeof(buff), "dir%d", i);
964 		assertEqualInt(0, stat(buff, &st));
965 		assertEqualInt(st.st_mtime, 123456 + i);
966 #if ARCHIVE_ACL_SUNOS_NFS4
967 		aclp = sunacl_get(ACE_GETACL, &aclcnt, 0, buff);
968 		failure("acl(\"%s\"): errno = %d (%s)", buff, errno,
969 		    strerror(errno));
970 		assert(aclp != NULL);
971 #elif ARCHIVE_ACL_LIBRICHACL
972 		richacl = richacl_get_file(buff);
973 		/* First and last two dir do not return a richacl */
974 		if ((i == 0 || i >= dircnt - 2) && richacl == NULL &&
975 		    errno == ENODATA)
976 			continue;
977 		failure("richacl_get_file(\"%s\"): errno = %d (%s)", buff,
978 		    errno, strerror(errno));
979 		assert(richacl != NULL);
980 #else
981 #if ARCHIVE_ACL_DARWIN
982 		acl = acl_get_file(buff, ACL_TYPE_EXTENDED);
983 #else
984 		acl = acl_get_file(buff, ACL_TYPE_NFS4);
985 #endif
986 		failure("acl_get_file(\"%s\"): errno = %d (%s)", buff, errno,
987 		    strerror(errno));
988 		assert(acl != (acl_t)NULL);
989 #endif
990 #if ARCHIVE_ACL_SUNOS_NFS4
991 		compare_acls(aclp, aclcnt, acls_dir, buff, i, i + 1);
992 		free(aclp);
993 		aclp = NULL;
994 #elif ARCHIVE_ACL_LIBRICHACL
995 		compare_acls(richacl, acls_dir, buff, i, i + 1);
996 		richacl_free(richacl);
997 #else
998 		compare_acls(acl, acls_dir, buff, i, i + 1);
999 		acl_free(acl);
1000 #endif
1001 	}
1002 
1003 	/* Verify "dirall" on disk. */
1004 	assertEqualInt(0, stat("dirall", &st));
1005 	assertEqualInt(st.st_mtime, 123456);
1006 #if ARCHIVE_ACL_SUNOS_NFS4
1007 	aclp = sunacl_get(ACE_GETACL, &aclcnt, 0, "dirall");
1008 	failure("acl(\"%s\"): errno = %d (%s)", "dirall", errno,
1009 	    strerror(errno));
1010 	assert(aclp != NULL);
1011 #elif ARCHIVE_ACL_LIBRICHACL
1012 	richacl = richacl_get_file("dirall");
1013 	failure("richacl_get_file(\"%s\"): errno = %d (%s)", "dirall",
1014 	    errno, strerror(errno));
1015 	assert(richacl != NULL);
1016 #else
1017 #if ARCHIVE_ACL_DARWIN
1018 	acl = acl_get_file("dirall", ACL_TYPE_EXTENDED);
1019 #else
1020 	acl = acl_get_file("dirall", ACL_TYPE_NFS4);
1021 #endif
1022 	failure("acl_get_file(\"%s\"): errno = %d (%s)", "dirall", errno,
1023 	    strerror(errno));
1024 	assert(acl != (acl_t)NULL);
1025 #endif
1026 #if ARCHIVE_ACL_SUNOS_NFS4
1027 	compare_acls(aclp, aclcnt, acls_dir, "dirall", 0, dircnt);
1028 	free(aclp);
1029 	aclp = NULL;
1030 #elif ARCHIVE_ACL_LIBRICHACL
1031 	compare_acls(richacl, acls_dir, "dirall", 0, dircnt);
1032 	richacl_free(richacl);
1033 #else
1034 	compare_acls(acl, acls_dir, "dirall", 0, dircnt);
1035 	acl_free(acl);
1036 #endif
1037 
1038 	/* Read and compare ACL via archive_read_disk */
1039 	a = archive_read_disk_new();
1040 	assert(a != NULL);
1041 	ae = archive_entry_new();
1042 	assert(ae != NULL);
1043 	archive_entry_set_pathname(ae, "testall");
1044 	assertEqualInt(ARCHIVE_OK,
1045 		       archive_read_disk_entry_from_file(a, ae, -1, NULL));
1046 	compare_entry_acls(ae, acls_reg, "testall", 0, acls_reg_cnt);
1047 	archive_entry_free(ae);
1048 	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
1049 
1050 	/* Read and compare ACL via archive_read_disk */
1051 	a = archive_read_disk_new();
1052 	assert(a != NULL);
1053 	ae = archive_entry_new();
1054 	assert(ae != NULL);
1055 	archive_entry_set_pathname(ae, "dirall");
1056 	assertEqualInt(ARCHIVE_OK,
1057 	archive_read_disk_entry_from_file(a, ae, -1, NULL));
1058 	compare_entry_acls(ae, acls_dir, "dirall", 0, acls_dir_cnt);
1059 	archive_entry_free(ae);
1060 	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
1061 #endif /* ARCHIVE_ACL_NFS4 */
1062 }
1063