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