Imported Upstream version 3.22.5
[platform/upstream/cmake.git] / Utilities / cmlibarchive / libarchive / archive_disk_acl_freebsd.c
1 /*-
2  * Copyright (c) 2003-2009 Tim Kientzle
3  * Copyright (c) 2010-2012 Michihiro NAKAJIMA
4  * Copyright (c) 2017 Martin Matuska
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 #include "archive_platform.h"
29
30 #if ARCHIVE_ACL_FREEBSD
31
32 #ifdef HAVE_ERRNO_H
33 #include <errno.h>
34 #endif
35 #ifdef HAVE_FCNTL_H
36 #include <fcntl.h>
37 #endif
38 #ifdef HAVE_SYS_TYPES_H
39 #include <sys/types.h>
40 #endif
41 #ifdef HAVE_SYS_ACL_H
42 #define _ACL_PRIVATE /* For debugging */
43 #include <sys/acl.h>
44 #endif
45
46 #include "archive_entry.h"
47 #include "archive_private.h"
48 #include "archive_read_disk_private.h"
49 #include "archive_write_disk_private.h"
50
51 typedef struct {
52         const int a_perm;       /* Libarchive permission or flag */
53         const int p_perm;       /* Platform permission or flag */
54 } acl_perm_map_t;
55
56 static const acl_perm_map_t acl_posix_perm_map[] = {
57         {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE},
58         {ARCHIVE_ENTRY_ACL_WRITE, ACL_WRITE},
59         {ARCHIVE_ENTRY_ACL_READ, ACL_READ},
60 };
61
62 static const int acl_posix_perm_map_size =
63     (int)(sizeof(acl_posix_perm_map)/sizeof(acl_posix_perm_map[0]));
64
65 #if ARCHIVE_ACL_FREEBSD_NFS4
66 static const acl_perm_map_t acl_nfs4_perm_map[] = {
67         {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE},
68         {ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA},
69         {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY},
70         {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA},
71         {ARCHIVE_ENTRY_ACL_ADD_FILE, ACL_ADD_FILE},
72         {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACL_APPEND_DATA},
73         {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACL_ADD_SUBDIRECTORY},
74         {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACL_READ_NAMED_ATTRS},
75         {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACL_WRITE_NAMED_ATTRS},
76         {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACL_DELETE_CHILD},
77         {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES},
78         {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES},
79         {ARCHIVE_ENTRY_ACL_DELETE, ACL_DELETE},
80         {ARCHIVE_ENTRY_ACL_READ_ACL, ACL_READ_ACL},
81         {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_ACL},
82         {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_WRITE_OWNER},
83         {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE}
84 };
85
86 static const int acl_nfs4_perm_map_size =
87     (int)(sizeof(acl_nfs4_perm_map)/sizeof(acl_nfs4_perm_map[0]));
88
89 static const acl_perm_map_t acl_nfs4_flag_map[] = {
90         {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT},
91         {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT},
92         {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_NO_PROPAGATE_INHERIT},
93         {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_INHERIT_ONLY},
94         {ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, ACL_ENTRY_SUCCESSFUL_ACCESS},
95         {ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, ACL_ENTRY_FAILED_ACCESS},
96 #ifdef ACL_ENTRY_INHERITED
97         {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACL_ENTRY_INHERITED}
98 #endif
99 };
100
101 static const int acl_nfs4_flag_map_size =
102     (int)(sizeof(acl_nfs4_flag_map)/sizeof(acl_nfs4_flag_map[0]));
103 #endif /* ARCHIVE_ACL_FREEBSD_NFS4 */
104
105 static int
106 translate_acl(struct archive_read_disk *a,
107     struct archive_entry *entry, acl_t acl, int default_entry_acl_type)
108 {
109 #if ARCHIVE_ACL_FREEBSD_NFS4
110         int brand;
111         acl_flagset_t    acl_flagset;
112         acl_entry_type_t acl_type;
113 #endif
114         acl_tag_t        acl_tag;
115         acl_entry_t      acl_entry;
116         acl_permset_t    acl_permset;
117         int              i, entry_acl_type, perm_map_size;
118         const acl_perm_map_t    *perm_map;
119         int              r, s, ae_id, ae_tag, ae_perm;
120         void            *q;
121         const char      *ae_name;
122
123 #if ARCHIVE_ACL_FREEBSD_NFS4
124         // FreeBSD "brands" ACLs as POSIX.1e or NFSv4
125         // Make sure the "brand" on this ACL is consistent
126         // with the default_entry_acl_type bits provided.
127         if (acl_get_brand_np(acl, &brand) != 0) {
128                 archive_set_error(&a->archive, errno,
129                     "Failed to read ACL brand");
130                 return (ARCHIVE_WARN);
131         }
132         switch (brand) {
133         case ACL_BRAND_POSIX:
134                 switch (default_entry_acl_type) {
135                 case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:
136                 case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:
137                         break;
138                 default:
139                         archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
140                             "Invalid ACL entry type for POSIX.1e ACL");
141                         return (ARCHIVE_WARN);
142                 }
143                 break;
144         case ACL_BRAND_NFS4:
145                 if (default_entry_acl_type & ~ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
146                         archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
147                             "Invalid ACL entry type for NFSv4 ACL");
148                         return (ARCHIVE_WARN);
149                 }
150                 break;
151         default:
152                 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
153                     "Unknown ACL brand");
154                 return (ARCHIVE_WARN);
155         }
156 #endif
157
158         s = acl_get_entry(acl, ACL_FIRST_ENTRY, &acl_entry);
159         if (s == -1) {
160                 archive_set_error(&a->archive, errno,
161                     "Failed to get first ACL entry");
162                 return (ARCHIVE_WARN);
163         }
164
165         while (s == 1) {
166                 ae_id = -1;
167                 ae_name = NULL;
168                 ae_perm = 0;
169
170                 if (acl_get_tag_type(acl_entry, &acl_tag) != 0) {
171                         archive_set_error(&a->archive, errno,
172                             "Failed to get ACL tag type");
173                         return (ARCHIVE_WARN);
174                 }
175                 switch (acl_tag) {
176                 case ACL_USER:
177                         q = acl_get_qualifier(acl_entry);
178                         if (q != NULL) {
179                                 ae_id = (int)*(uid_t *)q;
180                                 acl_free(q);
181                                 ae_name = archive_read_disk_uname(&a->archive,
182                                     ae_id);
183                         }
184                         ae_tag = ARCHIVE_ENTRY_ACL_USER;
185                         break;
186                 case ACL_GROUP:
187                         q = acl_get_qualifier(acl_entry);
188                         if (q != NULL) {
189                                 ae_id = (int)*(gid_t *)q;
190                                 acl_free(q);
191                                 ae_name = archive_read_disk_gname(&a->archive,
192                                     ae_id);
193                         }
194                         ae_tag = ARCHIVE_ENTRY_ACL_GROUP;
195                         break;
196                 case ACL_MASK:
197                         ae_tag = ARCHIVE_ENTRY_ACL_MASK;
198                         break;
199                 case ACL_USER_OBJ:
200                         ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
201                         break;
202                 case ACL_GROUP_OBJ:
203                         ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
204                         break;
205                 case ACL_OTHER:
206                         ae_tag = ARCHIVE_ENTRY_ACL_OTHER;
207                         break;
208 #if ARCHIVE_ACL_FREEBSD_NFS4
209                 case ACL_EVERYONE:
210                         ae_tag = ARCHIVE_ENTRY_ACL_EVERYONE;
211                         break;
212 #endif
213                 default:
214                         /* Skip types that libarchive can't support. */
215                         s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry);
216                         continue;
217                 }
218
219                 // XXX acl_type maps to allow/deny/audit/YYYY bits
220                 entry_acl_type = default_entry_acl_type;
221
222 #if ARCHIVE_ACL_FREEBSD_NFS4
223                 if (default_entry_acl_type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
224                         /*
225                          * acl_get_entry_type_np() fails with non-NFSv4 ACLs
226                          */
227                         if (acl_get_entry_type_np(acl_entry, &acl_type) != 0) {
228                                 archive_set_error(&a->archive, errno, "Failed "
229                                     "to get ACL type from a NFSv4 ACL entry");
230                                 return (ARCHIVE_WARN);
231                         }
232                         switch (acl_type) {
233                         case ACL_ENTRY_TYPE_ALLOW:
234                                 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW;
235                                 break;
236                         case ACL_ENTRY_TYPE_DENY:
237                                 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DENY;
238                                 break;
239                         case ACL_ENTRY_TYPE_AUDIT:
240                                 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_AUDIT;
241                                 break;
242                         case ACL_ENTRY_TYPE_ALARM:
243                                 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALARM;
244                                 break;
245                         default:
246                                 archive_set_error(&a->archive, errno,
247                                     "Invalid NFSv4 ACL entry type");
248                                 return (ARCHIVE_WARN);
249                         }
250
251                         /*
252                          * Libarchive stores "flag" (NFSv4 inheritance bits)
253                          * in the ae_perm bitmap.
254                          *
255                          * acl_get_flagset_np() fails with non-NFSv4 ACLs
256                          */
257                         if (acl_get_flagset_np(acl_entry, &acl_flagset) != 0) {
258                                 archive_set_error(&a->archive, errno,
259                                     "Failed to get flagset from a NFSv4 "
260                                     "ACL entry");
261                                 return (ARCHIVE_WARN);
262                         }
263                         for (i = 0; i < acl_nfs4_flag_map_size; ++i) {
264                                 r = acl_get_flag_np(acl_flagset,
265                                     acl_nfs4_flag_map[i].p_perm);
266                                 if (r == -1) {
267                                         archive_set_error(&a->archive, errno,
268                                             "Failed to check flag in a NFSv4 "
269                                             "ACL flagset");
270                                         return (ARCHIVE_WARN);
271                                 } else if (r)
272                                         ae_perm |= acl_nfs4_flag_map[i].a_perm;
273                         }
274                 }
275 #endif
276
277                 if (acl_get_permset(acl_entry, &acl_permset) != 0) {
278                         archive_set_error(&a->archive, errno,
279                             "Failed to get ACL permission set");
280                         return (ARCHIVE_WARN);
281                 }
282
283 #if ARCHIVE_ACL_FREEBSD_NFS4
284                 if (default_entry_acl_type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
285                         perm_map_size = acl_nfs4_perm_map_size;
286                         perm_map = acl_nfs4_perm_map;
287                 } else {
288 #endif
289                         perm_map_size = acl_posix_perm_map_size;
290                         perm_map = acl_posix_perm_map;
291 #if ARCHIVE_ACL_FREEBSD_NFS4
292                 }
293 #endif
294
295                 for (i = 0; i < perm_map_size; ++i) {
296                         r = acl_get_perm_np(acl_permset, perm_map[i].p_perm);
297                         if (r == -1) {
298                                 archive_set_error(&a->archive, errno,
299                                     "Failed to check permission in an ACL "
300                                     "permission set");
301                                 return (ARCHIVE_WARN);
302                         } else if (r)
303                                 ae_perm |= perm_map[i].a_perm;
304                 }
305
306                 archive_entry_acl_add_entry(entry, entry_acl_type,
307                                             ae_perm, ae_tag,
308                                             ae_id, ae_name);
309
310                 s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry);
311                 if (s == -1) {
312                         archive_set_error(&a->archive, errno,
313                             "Failed to get next ACL entry");
314                         return (ARCHIVE_WARN);
315                 }
316         }
317         return (ARCHIVE_OK);
318 }
319
320 static int
321 set_acl(struct archive *a, int fd, const char *name,
322     struct archive_acl *abstract_acl, __LA_MODE_T mode,
323     int ae_requested_type, const char *tname)
324 {
325         int              acl_type = 0;
326         acl_t            acl;
327         acl_entry_t      acl_entry;
328         acl_permset_t    acl_permset;
329 #if ARCHIVE_ACL_FREEBSD_NFS4
330         acl_flagset_t    acl_flagset;
331         int              r;
332 #endif
333         int              ret;
334         int              ae_type, ae_permset, ae_tag, ae_id;
335         int              perm_map_size;
336         const acl_perm_map_t    *perm_map;
337         uid_t            ae_uid;
338         gid_t            ae_gid;
339         const char      *ae_name;
340         int              entries;
341         int              i;
342
343         ret = ARCHIVE_OK;
344         entries = archive_acl_reset(abstract_acl, ae_requested_type);
345         if (entries == 0)
346                 return (ARCHIVE_OK);
347
348
349         switch (ae_requested_type) {
350         case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:
351                 acl_type = ACL_TYPE_ACCESS;
352                 break;
353         case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:
354                 acl_type = ACL_TYPE_DEFAULT;
355                 break;
356 #if ARCHIVE_ACL_FREEBSD_NFS4
357         case ARCHIVE_ENTRY_ACL_TYPE_NFS4:
358                 acl_type = ACL_TYPE_NFS4;
359                 break;
360 #endif
361         default:
362                 errno = ENOENT;
363                 archive_set_error(a, errno, "Unsupported ACL type");
364                 return (ARCHIVE_FAILED);
365         }
366
367         if (acl_type == ACL_TYPE_DEFAULT && !S_ISDIR(mode)) {
368                 errno = EINVAL;
369                 archive_set_error(a, errno,
370                     "Cannot set default ACL on non-directory");
371                 return (ARCHIVE_WARN);
372         }
373
374         acl = acl_init(entries);
375         if (acl == (acl_t)NULL) {
376                 archive_set_error(a, errno,
377                     "Failed to initialize ACL working storage");
378                 return (ARCHIVE_FAILED);
379         }
380
381         while (archive_acl_next(a, abstract_acl, ae_requested_type, &ae_type,
382                    &ae_permset, &ae_tag, &ae_id, &ae_name) == ARCHIVE_OK) {
383                 if (acl_create_entry(&acl, &acl_entry) != 0) {
384                         archive_set_error(a, errno,
385                             "Failed to create a new ACL entry");
386                         ret = ARCHIVE_FAILED;
387                         goto exit_free;
388                 }
389                 switch (ae_tag) {
390                 case ARCHIVE_ENTRY_ACL_USER:
391                         ae_uid = archive_write_disk_uid(a, ae_name, ae_id);
392                         acl_set_tag_type(acl_entry, ACL_USER);
393                         acl_set_qualifier(acl_entry, &ae_uid);
394                         break;
395                 case ARCHIVE_ENTRY_ACL_GROUP:
396                         ae_gid = archive_write_disk_gid(a, ae_name, ae_id);
397                         acl_set_tag_type(acl_entry, ACL_GROUP);
398                         acl_set_qualifier(acl_entry, &ae_gid);
399                         break;
400                 case ARCHIVE_ENTRY_ACL_USER_OBJ:
401                         acl_set_tag_type(acl_entry, ACL_USER_OBJ);
402                         break;
403                 case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
404                         acl_set_tag_type(acl_entry, ACL_GROUP_OBJ);
405                         break;
406                 case ARCHIVE_ENTRY_ACL_MASK:
407                         acl_set_tag_type(acl_entry, ACL_MASK);
408                         break;
409                 case ARCHIVE_ENTRY_ACL_OTHER:
410                         acl_set_tag_type(acl_entry, ACL_OTHER);
411                         break;
412 #if ARCHIVE_ACL_FREEBSD_NFS4
413                 case ARCHIVE_ENTRY_ACL_EVERYONE:
414                         acl_set_tag_type(acl_entry, ACL_EVERYONE);
415                         break;
416 #endif
417                 default:
418                         archive_set_error(a, ARCHIVE_ERRNO_MISC,
419                             "Unsupported ACL tag");
420                         ret = ARCHIVE_FAILED;
421                         goto exit_free;
422                 }
423
424 #if ARCHIVE_ACL_FREEBSD_NFS4
425                 r = 0;
426                 switch (ae_type) {
427                 case ARCHIVE_ENTRY_ACL_TYPE_ALLOW:
428                         r = acl_set_entry_type_np(acl_entry,
429                             ACL_ENTRY_TYPE_ALLOW);
430                         break;
431                 case ARCHIVE_ENTRY_ACL_TYPE_DENY:
432                         r = acl_set_entry_type_np(acl_entry,
433                             ACL_ENTRY_TYPE_DENY);
434                         break;
435                 case ARCHIVE_ENTRY_ACL_TYPE_AUDIT:
436                         r = acl_set_entry_type_np(acl_entry,
437                             ACL_ENTRY_TYPE_AUDIT);
438                         break;
439                 case ARCHIVE_ENTRY_ACL_TYPE_ALARM:
440                         r = acl_set_entry_type_np(acl_entry,
441                             ACL_ENTRY_TYPE_ALARM);
442                         break;
443                 case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:
444                 case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:
445                         // These don't translate directly into the system ACL.
446                         break;
447                 default:
448                         archive_set_error(a, ARCHIVE_ERRNO_MISC,
449                             "Unsupported ACL entry type");
450                         ret = ARCHIVE_FAILED;
451                         goto exit_free;
452                 }
453
454                 if (r != 0) {
455                         archive_set_error(a, errno,
456                             "Failed to set ACL entry type");
457                         ret = ARCHIVE_FAILED;
458                         goto exit_free;
459                 }
460 #endif
461
462                 if (acl_get_permset(acl_entry, &acl_permset) != 0) {
463                         archive_set_error(a, errno,
464                             "Failed to get ACL permission set");
465                         ret = ARCHIVE_FAILED;
466                         goto exit_free;
467                 }
468                 if (acl_clear_perms(acl_permset) != 0) {
469                         archive_set_error(a, errno,
470                             "Failed to clear ACL permissions");
471                         ret = ARCHIVE_FAILED;
472                         goto exit_free;
473                 }
474 #if ARCHIVE_ACL_FREEBSD_NFS4
475                 if (ae_requested_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
476                         perm_map_size = acl_nfs4_perm_map_size;
477                         perm_map = acl_nfs4_perm_map;
478                 } else {
479 #endif
480                         perm_map_size = acl_posix_perm_map_size;
481                         perm_map = acl_posix_perm_map;
482 #if ARCHIVE_ACL_FREEBSD_NFS4
483                 }
484 #endif
485
486                 for (i = 0; i < perm_map_size; ++i) {
487                         if (ae_permset & perm_map[i].a_perm) {
488                                 if (acl_add_perm(acl_permset,
489                                     perm_map[i].p_perm) != 0) {
490                                         archive_set_error(a, errno,
491                                             "Failed to add ACL permission");
492                                         ret = ARCHIVE_FAILED;
493                                         goto exit_free;
494                                 }
495                         }
496                 }
497
498 #if ARCHIVE_ACL_FREEBSD_NFS4
499                 if (ae_requested_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
500                         /*
501                          * acl_get_flagset_np() fails with non-NFSv4 ACLs
502                          */
503                         if (acl_get_flagset_np(acl_entry, &acl_flagset) != 0) {
504                                 archive_set_error(a, errno,
505                                     "Failed to get flagset from an NFSv4 "
506                                     "ACL entry");
507                                 ret = ARCHIVE_FAILED;
508                                 goto exit_free;
509                         }
510                         if (acl_clear_flags_np(acl_flagset) != 0) {
511                                 archive_set_error(a, errno,
512                                     "Failed to clear flags from an NFSv4 "
513                                     "ACL flagset");
514                                 ret = ARCHIVE_FAILED;
515                                 goto exit_free;
516                         }
517                         for (i = 0; i < acl_nfs4_flag_map_size; ++i) {
518                                 if (ae_permset & acl_nfs4_flag_map[i].a_perm) {
519                                         if (acl_add_flag_np(acl_flagset,
520                                             acl_nfs4_flag_map[i].p_perm) != 0) {
521                                                 archive_set_error(a, errno,
522                                                     "Failed to add flag to "
523                                                     "NFSv4 ACL flagset");
524                                                 ret = ARCHIVE_FAILED;
525                                                 goto exit_free;
526                                         }
527                                 }
528                         }
529                 }
530 #endif
531         }
532
533         /* Try restoring the ACL through 'fd' if we can. */
534         if (fd >= 0) {
535                 if (acl_set_fd_np(fd, acl, acl_type) == 0)
536                         ret = ARCHIVE_OK;
537                 else {
538                         if (errno == EOPNOTSUPP) {
539                                 /* Filesystem doesn't support ACLs */
540                                 ret = ARCHIVE_OK;
541                         } else {
542                                 archive_set_error(a, errno,
543                                     "Failed to set acl on fd: %s", tname);
544                                 ret = ARCHIVE_WARN;
545                         }
546                 }
547         }
548 #if HAVE_ACL_SET_LINK_NP
549         else if (acl_set_link_np(name, acl_type, acl) != 0)
550 #else
551         /* FreeBSD older than 8.0 */
552         else if (S_ISLNK(mode)) {
553             /* acl_set_file() follows symbolic links, skip */
554             ret = ARCHIVE_OK;
555         } else if (acl_set_file(name, acl_type, acl) != 0)
556 #endif
557         {
558                 if (errno == EOPNOTSUPP) {
559                         /* Filesystem doesn't support ACLs */
560                         ret = ARCHIVE_OK;
561                 } else {
562                         archive_set_error(a, errno, "Failed to set acl: %s",
563                             tname);
564                         ret = ARCHIVE_WARN;
565                 }
566         }
567 exit_free:
568         acl_free(acl);
569         return (ret);
570 }
571
572 int
573 archive_read_disk_entry_setup_acls(struct archive_read_disk *a,
574     struct archive_entry *entry, int *fd)
575 {
576         const char      *accpath;
577         acl_t           acl;
578         int             r;
579
580         accpath = NULL;
581
582         if (*fd < 0) {
583                 accpath = archive_read_disk_entry_setup_path(a, entry, fd);
584                 if (accpath == NULL)
585                         return (ARCHIVE_WARN);
586         }
587
588         archive_entry_acl_clear(entry);
589
590         acl = NULL;
591
592 #if ARCHIVE_ACL_FREEBSD_NFS4
593         /* Try NFSv4 ACL first. */
594         if (*fd >= 0)
595                 acl = acl_get_fd_np(*fd, ACL_TYPE_NFS4);
596         else if (!a->follow_symlinks)
597                 acl = acl_get_link_np(accpath, ACL_TYPE_NFS4);
598         else
599                 acl = acl_get_file(accpath, ACL_TYPE_NFS4);
600
601         /* Ignore "trivial" ACLs that just mirror the file mode. */
602         if (acl != NULL && acl_is_trivial_np(acl, &r) == 0 && r == 1) {
603                 acl_free(acl);
604                 acl = NULL;
605                 return (ARCHIVE_OK);
606         }
607
608         if (acl != NULL) {
609                 r = translate_acl(a, entry, acl, ARCHIVE_ENTRY_ACL_TYPE_NFS4);
610                 acl_free(acl);
611                 acl = NULL;
612
613                 if (r != ARCHIVE_OK) {
614                         archive_set_error(&a->archive, errno,
615                             "Couldn't translate NFSv4 ACLs");
616                 }
617
618                 return (r);
619         }
620 #endif
621
622         /* Retrieve access ACL from file. */
623         if (*fd >= 0)
624                 acl = acl_get_fd_np(*fd, ACL_TYPE_ACCESS);
625 #if HAVE_ACL_GET_LINK_NP
626         else if (!a->follow_symlinks)
627                 acl = acl_get_link_np(accpath, ACL_TYPE_ACCESS);
628 #else
629         else if ((!a->follow_symlinks)
630             && (archive_entry_filetype(entry) == AE_IFLNK))
631                 /* We can't get the ACL of a symlink, so we assume it can't
632                    have one. */
633                 acl = NULL;
634 #endif
635         else
636                 acl = acl_get_file(accpath, ACL_TYPE_ACCESS);
637
638 #if HAVE_ACL_IS_TRIVIAL_NP
639         /* Ignore "trivial" ACLs that just mirror the file mode. */
640         if (acl != NULL && acl_is_trivial_np(acl, &r) == 0 && r == 1) {
641                 acl_free(acl);
642                 acl = NULL;
643         }
644 #endif
645
646         if (acl != NULL) {
647                 r = translate_acl(a, entry, acl, ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
648                 acl_free(acl);
649                 acl = NULL;
650
651                 if (r != ARCHIVE_OK) {
652                         archive_set_error(&a->archive, errno,
653                             "Couldn't translate access ACLs");
654                         return (r);
655                 }
656         }
657
658         /* Only directories can have default ACLs. */
659         if (S_ISDIR(archive_entry_mode(entry))) {
660                 if (*fd >= 0)
661                         acl = acl_get_fd_np(*fd, ACL_TYPE_DEFAULT);
662                 else
663                         acl = acl_get_file(accpath, ACL_TYPE_DEFAULT);
664                 if (acl != NULL) {
665                         r = translate_acl(a, entry, acl,
666                             ARCHIVE_ENTRY_ACL_TYPE_DEFAULT);
667                         acl_free(acl);
668                         if (r != ARCHIVE_OK) {
669                                 archive_set_error(&a->archive, errno,
670                                     "Couldn't translate default ACLs");
671                                 return (r);
672                         }
673                 }
674         }
675         return (ARCHIVE_OK);
676 }
677
678 int
679 archive_write_disk_set_acls(struct archive *a, int fd, const char *name,
680     struct archive_acl *abstract_acl, __LA_MODE_T mode)
681 {
682         int             ret = ARCHIVE_OK;
683
684         (void)mode;     /* UNUSED */
685
686         if ((archive_acl_types(abstract_acl)
687             & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) {
688                 if ((archive_acl_types(abstract_acl)
689                     & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
690                         ret = set_acl(a, fd, name, abstract_acl, mode,
691                             ARCHIVE_ENTRY_ACL_TYPE_ACCESS, "access");
692                         if (ret != ARCHIVE_OK)
693                                 return (ret);
694                 }
695                 if ((archive_acl_types(abstract_acl)
696                     & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0)
697                         ret = set_acl(a, fd, name, abstract_acl, mode,
698                             ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, "default");
699
700                 /* Simultaneous POSIX.1e and NFSv4 is not supported */
701                 return (ret);
702         }
703 #if ARCHIVE_ACL_FREEBSD_NFS4
704         else if ((archive_acl_types(abstract_acl) &
705             ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) {
706                 ret = set_acl(a, fd, name, abstract_acl, mode,
707                     ARCHIVE_ENTRY_ACL_TYPE_NFS4, "nfs4");
708         }
709 #endif
710         return (ret);
711 }
712 #endif  /* ARCHIVE_ACL_FREEBSD */