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 	case ACL_ENTRY_TYPE_ALARM:
638 		if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_ALARM)
639 			return (0);
640 	default:
641 		return (0);
642 	}
643 
644 	switch (tag_type) {
645 	case ACL_USER_OBJ:
646 		if (myacl->tag != ARCHIVE_ENTRY_ACL_USER_OBJ) return (0);
647 		break;
648 	case ACL_USER:
649 		if (myacl->tag != ARCHIVE_ENTRY_ACL_USER)
650 			return (0);
651 		up = acl_get_qualifier(aclent);
652 		u = *up;
653 		acl_free(up);
654 		if ((uid_t)myacl->qual != u)
655 			return (0);
656 		break;
657 	case ACL_GROUP_OBJ:
658 		if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP_OBJ) return (0);
659 		break;
660 	case ACL_GROUP:
661 		if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP)
662 			return (0);
663 		gp = acl_get_qualifier(aclent);
664 		g = *gp;
665 		acl_free(gp);
666 		if ((gid_t)myacl->qual != g)
667 			return (0);
668 		break;
669 	case ACL_MASK:
670 		if (myacl->tag != ARCHIVE_ENTRY_ACL_MASK) return (0);
671 		break;
672 	case ACL_EVERYONE:
673 		if (myacl->tag != ARCHIVE_ENTRY_ACL_EVERYONE) return (0);
674 		break;
675 	}
676 	return (1);
677 }
678 #endif	/* various ARCHIVE_ACL_NFS4 implementations */
679 
680 static void
681 compare_acls(
682 #if ARCHIVE_ACL_SUNOS_NFS4
683     void *aclp,
684     int aclcnt,
685 #elif ARCHIVE_ACL_LIBRICHACL
686     struct richacl *richacl,
687 #else
688     acl_t acl,
689 #endif
690     struct myacl_t *myacls, const char *filename, int start, int end)
691 {
692 	int *marker;
693 	int matched;
694 	int i, n;
695 #if ARCHIVE_ACL_SUNOS_NFS4
696 	int e;
697 	ace_t *acl_entry;
698 #elif ARCHIVE_ACL_LIBRICHACL
699 	int e;
700 	struct richace *acl_entry;
701 	int aclcnt;
702 #else
703 	int entry_id = ACL_FIRST_ENTRY;
704 	acl_entry_t acl_entry;
705 #if ARCHIVE_ACL_DARWIN
706 	const int acl_get_entry_ret = 0;
707 #else
708 	const int acl_get_entry_ret = 1;
709 #endif
710 #endif
711 
712 #if ARCHIVE_ACL_SUNOS_NFS4
713 	if (aclp == NULL)
714 		return;
715 #elif ARCHIVE_ACL_LIBRICHACL
716 	if (richacl == NULL)
717 		return;
718 	aclcnt = richacl->a_count;
719 #else
720 	if (acl == NULL)
721 		return;
722 #endif
723 
724 	n = end - start;
725 	marker = malloc(sizeof(marker[0]) * (n + 1));
726 	for (i = 0; i < n; i++)
727 		marker[i] = i + start;
728 #if !ARCHIVE_ACL_DARWIN
729 	/* Always include the first ACE. */
730 	if (start > 0) {
731 	  marker[n] = 0;
732 	  ++n;
733 	}
734 #endif
735 
736 	/*
737 	 * Iterate over acls in system acl object, try to match each
738 	 * one with an item in the myacls array.
739 	 */
740 #if ARCHIVE_ACL_SUNOS_NFS4 || ARCHIVE_ACL_LIBRICHACL
741 	for (e = 0; e < aclcnt; e++)
742 #else
743 	while (acl_get_entry_ret == acl_get_entry(acl, entry_id, &acl_entry))
744 #endif
745 	{
746 #if ARCHIVE_ACL_SUNOS_NFS4
747 		acl_entry = &((ace_t *)aclp)[e];
748 #elif ARCHIVE_ACL_LIBRICHACL
749 		acl_entry = &(richacl->a_entries[e]);
750 #else
751 		/* After the first time... */
752 		entry_id = ACL_NEXT_ENTRY;
753 #endif
754 		/* Search for a matching entry (tag and qualifier) */
755 		for (i = 0, matched = 0; i < n && !matched; i++) {
756 			if (acl_match(acl_entry, &myacls[marker[i]])) {
757 				/* We found a match; remove it. */
758 				marker[i] = marker[n - 1];
759 				n--;
760 				matched = 1;
761 			}
762 		}
763 
764 		failure("ACL entry on file %s that shouldn't be there",
765 		    filename);
766 		assert(matched == 1);
767 	}
768 
769 	/* Dump entries in the myacls array that weren't in the system acl. */
770 	for (i = 0; i < n; ++i) {
771 		failure(" ACL entry %d missing from %s: "
772 		    "type=%#010x,permset=%#010x,tag=%d,qual=%d,name=``%s''\n",
773 		    marker[i], filename,
774 		    myacls[marker[i]].type, myacls[marker[i]].permset,
775 		    myacls[marker[i]].tag, myacls[marker[i]].qual,
776 		    myacls[marker[i]].name);
777 		assert(0); /* Record this as a failure. */
778 	}
779 	free(marker);
780 }
781 
782 static void
783 compare_entry_acls(struct archive_entry *ae, struct myacl_t *myacls, const char *filename, int start, int end)
784 {
785 	int *marker;
786 	int matched;
787 	int i, n;
788 	int type, permset, tag, qual;
789 	const char *name;
790 
791 	/* Count ACL entries in myacls array and allocate an indirect array. */
792 	n = end - start;
793 	marker = malloc(sizeof(marker[0]) * (n + 1));
794 	for (i = 0; i < n; i++)
795 		marker[i] = i + start;
796 	/* Always include the first ACE. */
797 	if (start > 0) {
798 	  marker[n] = 0;
799 	  ++n;
800 	}
801 
802 	/*
803 	 * Iterate over acls in entry, try to match each
804 	 * one with an item in the myacls array.
805 	 */
806 	assertEqualInt(n, archive_entry_acl_reset(ae,
807 	    ARCHIVE_ENTRY_ACL_TYPE_NFS4));
808 	while (ARCHIVE_OK == archive_entry_acl_next(ae,
809 	    ARCHIVE_ENTRY_ACL_TYPE_NFS4, &type, &permset, &tag, &qual, &name)) {
810 
811 		/* Search for a matching entry (tag and qualifier) */
812 		for (i = 0, matched = 0; i < n && !matched; i++) {
813 			if (tag == myacls[marker[i]].tag
814 			    && qual == myacls[marker[i]].qual
815 			    && permset == myacls[marker[i]].permset
816 			    && type == myacls[marker[i]].type) {
817 				/* We found a match; remove it. */
818 				marker[i] = marker[n - 1];
819 				n--;
820 				matched = 1;
821 			}
822 		}
823 
824 		failure("ACL entry on file that shouldn't be there: "
825 			"type=%#010x,permset=%#010x,tag=%d,qual=%d",
826 			type,permset,tag,qual);
827 		assert(matched == 1);
828 	}
829 
830 	/* Dump entries in the myacls array that weren't in the system acl. */
831 	for (i = 0; i < n; ++i) {
832 		failure(" ACL entry %d missing from %s: "
833 		    "type=%#010x,permset=%#010x,tag=%d,qual=%d,name=``%s''\n",
834 		    marker[i], filename,
835 		    myacls[marker[i]].type, myacls[marker[i]].permset,
836 		    myacls[marker[i]].tag, myacls[marker[i]].qual,
837 		    myacls[marker[i]].name);
838 		assert(0); /* Record this as a failure. */
839 	}
840 	free(marker);
841 }
842 #endif	/* ARCHIVE_ACL_NFS4 */
843 
844 /*
845  * Verify ACL restore-to-disk.  This test is Platform-specific.
846  */
847 
848 DEFINE_TEST(test_acl_platform_nfs4)
849 {
850 #if !ARCHIVE_ACL_NFS4
851 	skipping("NFS4 ACLs are not supported on this platform");
852 #else /* ARCHIVE_ACL_NFS4 */
853 	char buff[64];
854 	int i;
855 	struct stat st;
856 	struct archive *a;
857 	struct archive_entry *ae;
858 #if ARCHIVE_ACL_DARWIN /* On MacOS we skip trivial ACLs in some tests */
859 	const int regcnt = acls_reg_cnt - 4;
860 	const int dircnt = acls_dir_cnt - 4;
861 #else
862 	const int regcnt = acls_reg_cnt;
863 	const int dircnt = acls_dir_cnt;
864 #endif
865 #if ARCHIVE_ACL_SUNOS_NFS4
866 	void *aclp;
867 	int aclcnt;
868 #elif ARCHIVE_ACL_LIBRICHACL
869 	struct richacl *richacl;
870 #else	/* !ARCHIVE_ACL_SUNOS_NFS4 */
871 	acl_t acl;
872 #endif
873 
874 	assertMakeFile("pretest", 0644, "a");
875 
876 	if (setTestAcl("pretest") != ARCHIVE_TEST_ACL_TYPE_NFS4) {
877 		skipping("NFS4 ACLs are not writable on this filesystem");
878 		return;
879 	}
880 
881 	/* Create a write-to-disk object. */
882 	assert(NULL != (a = archive_write_disk_new()));
883 	archive_write_disk_set_options(a,
884 	    ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_ACL);
885 
886 	/* Populate an archive entry with some metadata, including ACL info */
887 	ae = archive_entry_new();
888 	assert(ae != NULL);
889 	archive_entry_set_pathname(ae, "testall");
890 	archive_entry_set_filetype(ae, AE_IFREG);
891 	archive_entry_set_perm(ae, 0654);
892 	archive_entry_set_mtime(ae, 123456, 7890);
893 	archive_entry_set_size(ae, 0);
894 	set_acls(ae, acls_reg, 0, acls_reg_cnt);
895 
896 	/* Write the entry to disk, including ACLs. */
897 	assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
898 
899 	/* Likewise for a dir. */
900 	archive_entry_set_pathname(ae, "dirall");
901 	archive_entry_set_filetype(ae, AE_IFDIR);
902 	archive_entry_set_perm(ae, 0654);
903 	archive_entry_set_mtime(ae, 123456, 7890);
904 	set_acls(ae, acls_dir, 0, acls_dir_cnt);
905 	assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
906 
907 	for (i = 0; i < acls_dir_cnt; ++i) {
908 	  sprintf(buff, "dir%d", i);
909 	  archive_entry_set_pathname(ae, buff);
910 	  archive_entry_set_filetype(ae, AE_IFDIR);
911 	  archive_entry_set_perm(ae, 0654);
912 	  archive_entry_set_mtime(ae, 123456 + i, 7891 + i);
913 	  set_acls(ae, acls_dir, i, i + 1);
914 	  assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
915 	}
916 
917 	archive_entry_free(ae);
918 
919 	/* Close the archive. */
920 	assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
921 	assertEqualInt(ARCHIVE_OK, archive_write_free(a));
922 
923 	/* Verify the data on disk. */
924 	assertEqualInt(0, stat("testall", &st));
925 	assertEqualInt(st.st_mtime, 123456);
926 #if ARCHIVE_ACL_SUNOS_NFS4
927 	aclp = sunacl_get(ACE_GETACL, &aclcnt, 0, "testall");
928 	failure("acl(\"%s\"): errno = %d (%s)", "testall", errno,
929 	    strerror(errno));
930 	assert(aclp != NULL);
931 #elif ARCHIVE_ACL_LIBRICHACL
932 	richacl = richacl_get_file("testall");
933 	failure("richacl_get_file(\"%s\"): errno = %d (%s)", "testall", errno,
934 	    strerror(errno));
935 	assert(richacl != NULL);
936 #else
937 #if ARCHIVE_ACL_DARWIN
938 	acl = acl_get_file("testall", ACL_TYPE_EXTENDED);
939 #else
940 	acl = acl_get_file("testall", ACL_TYPE_NFS4);
941 #endif
942 	failure("acl_get_file(\"%s\"): errno = %d (%s)", "testall", errno,
943 	    strerror(errno));
944 	assert(acl != (acl_t)NULL);
945 #endif
946 #if ARCHIVE_ACL_SUNOS_NFS4
947 	compare_acls(aclp, aclcnt, acls_reg, "testall", 0, regcnt);
948 	free(aclp);
949 	aclp = NULL;
950 #elif ARCHIVE_ACL_LIBRICHACL
951 	compare_acls(richacl, acls_reg, "testall", 0, regcnt);
952 	richacl_free(richacl);
953 #else
954 	compare_acls(acl, acls_reg, "testall", 0, regcnt);
955 	acl_free(acl);
956 #endif
957 
958 
959 	/* Verify single-permission dirs on disk. */
960 	for (i = 0; i < dircnt; ++i) {
961 		sprintf(buff, "dir%d", i);
962 		assertEqualInt(0, stat(buff, &st));
963 		assertEqualInt(st.st_mtime, 123456 + i);
964 #if ARCHIVE_ACL_SUNOS_NFS4
965 		aclp = sunacl_get(ACE_GETACL, &aclcnt, 0, buff);
966 		failure("acl(\"%s\"): errno = %d (%s)", buff, errno,
967 		    strerror(errno));
968 		assert(aclp != NULL);
969 #elif ARCHIVE_ACL_LIBRICHACL
970 		richacl = richacl_get_file(buff);
971 		/* First and last two dir do not return a richacl */
972 		if ((i == 0 || i >= dircnt - 2) && richacl == NULL &&
973 		    errno == ENODATA)
974 			continue;
975 		failure("richacl_get_file(\"%s\"): errno = %d (%s)", buff,
976 		    errno, strerror(errno));
977 		assert(richacl != NULL);
978 #else
979 #if ARCHIVE_ACL_DARWIN
980 		acl = acl_get_file(buff, ACL_TYPE_EXTENDED);
981 #else
982 		acl = acl_get_file(buff, ACL_TYPE_NFS4);
983 #endif
984 		failure("acl_get_file(\"%s\"): errno = %d (%s)", buff, errno,
985 		    strerror(errno));
986 		assert(acl != (acl_t)NULL);
987 #endif
988 #if ARCHIVE_ACL_SUNOS_NFS4
989 		compare_acls(aclp, aclcnt, acls_dir, buff, i, i + 1);
990 		free(aclp);
991 		aclp = NULL;
992 #elif ARCHIVE_ACL_LIBRICHACL
993 		compare_acls(richacl, acls_dir, buff, i, i + 1);
994 		richacl_free(richacl);
995 #else
996 		compare_acls(acl, acls_dir, buff, i, i + 1);
997 		acl_free(acl);
998 #endif
999 	}
1000 
1001 	/* Verify "dirall" on disk. */
1002 	assertEqualInt(0, stat("dirall", &st));
1003 	assertEqualInt(st.st_mtime, 123456);
1004 #if ARCHIVE_ACL_SUNOS_NFS4
1005 	aclp = sunacl_get(ACE_GETACL, &aclcnt, 0, "dirall");
1006 	failure("acl(\"%s\"): errno = %d (%s)", "dirall", errno,
1007 	    strerror(errno));
1008 	assert(aclp != NULL);
1009 #elif ARCHIVE_ACL_LIBRICHACL
1010 	richacl = richacl_get_file("dirall");
1011 	failure("richacl_get_file(\"%s\"): errno = %d (%s)", "dirall",
1012 	    errno, strerror(errno));
1013 	assert(richacl != NULL);
1014 #else
1015 #if ARCHIVE_ACL_DARWIN
1016 	acl = acl_get_file("dirall", ACL_TYPE_EXTENDED);
1017 #else
1018 	acl = acl_get_file("dirall", ACL_TYPE_NFS4);
1019 #endif
1020 	failure("acl_get_file(\"%s\"): errno = %d (%s)", "dirall", errno,
1021 	    strerror(errno));
1022 	assert(acl != (acl_t)NULL);
1023 #endif
1024 #if ARCHIVE_ACL_SUNOS_NFS4
1025 	compare_acls(aclp, aclcnt, acls_dir, "dirall", 0, dircnt);
1026 	free(aclp);
1027 	aclp = NULL;
1028 #elif ARCHIVE_ACL_LIBRICHACL
1029 	compare_acls(richacl, acls_dir, "dirall", 0, dircnt);
1030 	richacl_free(richacl);
1031 #else
1032 	compare_acls(acl, acls_dir, "dirall", 0, dircnt);
1033 	acl_free(acl);
1034 #endif
1035 
1036 	/* Read and compare ACL via archive_read_disk */
1037 	a = archive_read_disk_new();
1038 	assert(a != NULL);
1039 	ae = archive_entry_new();
1040 	assert(ae != NULL);
1041 	archive_entry_set_pathname(ae, "testall");
1042 	assertEqualInt(ARCHIVE_OK,
1043 		       archive_read_disk_entry_from_file(a, ae, -1, NULL));
1044 	compare_entry_acls(ae, acls_reg, "testall", 0, acls_reg_cnt);
1045 	archive_entry_free(ae);
1046 	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
1047 
1048 	/* Read and compare ACL via archive_read_disk */
1049 	a = archive_read_disk_new();
1050 	assert(a != NULL);
1051 	ae = archive_entry_new();
1052 	assert(ae != NULL);
1053 	archive_entry_set_pathname(ae, "dirall");
1054 	assertEqualInt(ARCHIVE_OK,
1055 	archive_read_disk_entry_from_file(a, ae, -1, NULL));
1056 	compare_entry_acls(ae, acls_dir, "dirall", 0, acls_dir_cnt);
1057 	archive_entry_free(ae);
1058 	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
1059 #endif /* ARCHIVE_ACL_NFS4 */
1060 }
1061