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