]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - contrib/libarchive/libarchive/archive_write_disk_acl.c
MFC r315516
[FreeBSD/stable/10.git] / contrib / libarchive / libarchive / archive_write_disk_acl.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  *    in this position and unchanged.
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
27 #include "archive_platform.h"
28 __FBSDID("$FreeBSD: head/lib/libarchive/archive_write_disk.c 201159 2009-12-29 05:35:40Z kientzle $");
29
30 #ifdef HAVE_SYS_TYPES_H
31 #include <sys/types.h>
32 #endif
33 #ifdef HAVE_SYS_ACL_H
34 #define _ACL_PRIVATE /* For debugging */
35 #include <sys/acl.h>
36 #endif
37 #if HAVE_DARWIN_ACL
38 #include <membership.h>
39 #endif
40 #ifdef HAVE_ERRNO_H
41 #include <errno.h>
42 #endif
43
44 #include "archive.h"
45 #include "archive_entry.h"
46 #include "archive_acl_private.h"
47 #include "archive_write_disk_private.h"
48
49 #if !HAVE_POSIX_ACL && !HAVE_NFS4_ACL
50 /* Default empty function body to satisfy mainline code. */
51 int
52 archive_write_disk_set_acls(struct archive *a, int fd, const char *name,
53          struct archive_acl *abstract_acl)
54 {
55         (void)a; /* UNUSED */
56         (void)fd; /* UNUSED */
57         (void)name; /* UNUSED */
58         (void)abstract_acl; /* UNUSED */
59         return (ARCHIVE_OK);
60 }
61
62 #else /* HAVE_POSIX_ACL || HAVE_NFS4_ACL */
63
64 #if HAVE_DARWIN_ACL
65 #define ARCHIVE_PLATFORM_ACL_TYPE_NFS4  ACL_TYPE_EXTENDED
66 #elif HAVE_FREEBSD_NFS4_ACL
67 #define ARCHIVE_PLATFORM_ACL_TYPE_NFS4  ACL_TYPE_NFS4
68 #endif
69
70 static int      set_acl(struct archive *, int fd, const char *,
71                         struct archive_acl *,
72 #if !HAVE_SUN_ACL
73                         acl_type_t,
74 #endif
75                         int archive_entry_acl_type, const char *tn);
76
77 int
78 archive_write_disk_set_acls(struct archive *a, int fd, const char *name,
79          struct archive_acl *abstract_acl)
80 {
81         int             ret = ARCHIVE_OK;
82
83 #if !HAVE_DARWIN_ACL
84         if ((archive_acl_types(abstract_acl)
85             & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) {
86 #if HAVE_SUN_ACL
87                 /* Solaris writes POSIX.1e access and default ACLs together */
88                 ret = set_acl(a, fd, name, abstract_acl,
89                     ARCHIVE_ENTRY_ACL_TYPE_POSIX1E, "posix1e");
90 #else   /* HAVE_POSIX_ACL */
91                 if ((archive_acl_types(abstract_acl)
92                     & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
93                         ret = set_acl(a, fd, name, abstract_acl,
94                             ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
95                             "access");
96                         if (ret != ARCHIVE_OK)
97                                 return (ret);
98                 }
99                 if ((archive_acl_types(abstract_acl)
100                     & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0)
101                         ret = set_acl(a, fd, name, abstract_acl,
102                             ACL_TYPE_DEFAULT, ARCHIVE_ENTRY_ACL_TYPE_DEFAULT,
103                             "default");
104 #endif  /* !HAVE_SUN_ACL */
105                 /* Simultaneous POSIX.1e and NFSv4 is not supported */
106                 return (ret);
107         }
108 #endif  /* !HAVE_DARWIN_ACL */
109 #if HAVE_NFS4_ACL
110         if ((archive_acl_types(abstract_acl) &
111             ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) {
112                 ret = set_acl(a, fd, name, abstract_acl,
113 #if !HAVE_SUN_ACL
114                     ARCHIVE_PLATFORM_ACL_TYPE_NFS4,
115 #endif
116                     ARCHIVE_ENTRY_ACL_TYPE_NFS4, "nfs4");
117         }
118 #endif  /* HAVE_NFS4_ACL */
119         return (ret);
120 }
121
122 #if !HAVE_SUN_ACL || HAVE_SUN_NFS4_ACL
123 /*
124  * Translate system ACL permissions into libarchive internal structure
125  */
126 static const struct {
127         const int archive_perm;
128         const int platform_perm;
129 } acl_perm_map[] = {
130 #if HAVE_SUN_NFS4_ACL   /* Solaris NFSv4 ACL permissions */
131         {ARCHIVE_ENTRY_ACL_EXECUTE, ACE_EXECUTE},
132         {ARCHIVE_ENTRY_ACL_READ_DATA, ACE_READ_DATA},
133         {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACE_LIST_DIRECTORY},
134         {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACE_WRITE_DATA},
135         {ARCHIVE_ENTRY_ACL_ADD_FILE, ACE_ADD_FILE},
136         {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACE_APPEND_DATA},
137         {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACE_ADD_SUBDIRECTORY},
138         {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACE_READ_NAMED_ATTRS},
139         {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACE_WRITE_NAMED_ATTRS},
140         {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACE_DELETE_CHILD},
141         {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACE_READ_ATTRIBUTES},
142         {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACE_WRITE_ATTRIBUTES},
143         {ARCHIVE_ENTRY_ACL_DELETE, ACE_DELETE},
144         {ARCHIVE_ENTRY_ACL_READ_ACL, ACE_READ_ACL},
145         {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACE_WRITE_ACL},
146         {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACE_WRITE_OWNER},
147         {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACE_SYNCHRONIZE}
148 #elif HAVE_DARWIN_ACL   /* MacOS ACL permissions */
149         {ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA},
150         {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY},
151         {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA},
152         {ARCHIVE_ENTRY_ACL_ADD_FILE, ACL_ADD_FILE},
153         {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE},
154         {ARCHIVE_ENTRY_ACL_DELETE, ACL_DELETE},
155         {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACL_APPEND_DATA},
156         {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACL_ADD_SUBDIRECTORY},
157         {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACL_DELETE_CHILD},
158         {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES},
159         {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES},
160         {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACL_READ_EXTATTRIBUTES},
161         {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACL_WRITE_EXTATTRIBUTES},
162         {ARCHIVE_ENTRY_ACL_READ_ACL, ACL_READ_SECURITY},
163         {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_SECURITY},
164         {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_CHANGE_OWNER},
165 #if HAVE_DECL_ACL_SYNCHRONIZE
166         {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE}
167 #endif
168 #else   /* POSIX.1e ACL permissions */
169         {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE},
170         {ARCHIVE_ENTRY_ACL_WRITE, ACL_WRITE},
171         {ARCHIVE_ENTRY_ACL_READ, ACL_READ},
172 #if HAVE_FREEBSD_NFS4_ACL       /* FreeBSD NFSv4 ACL permissions */
173         {ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA},
174         {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY},
175         {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA},
176         {ARCHIVE_ENTRY_ACL_ADD_FILE, ACL_ADD_FILE},
177         {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACL_APPEND_DATA},
178         {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACL_ADD_SUBDIRECTORY},
179         {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACL_READ_NAMED_ATTRS},
180         {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACL_WRITE_NAMED_ATTRS},
181         {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACL_DELETE_CHILD},
182         {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES},
183         {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES},
184         {ARCHIVE_ENTRY_ACL_DELETE, ACL_DELETE},
185         {ARCHIVE_ENTRY_ACL_READ_ACL, ACL_READ_ACL},
186         {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_ACL},
187         {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_WRITE_OWNER},
188         {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE}
189 #endif
190 #endif  /* !HAVE_SUN_ACL && !HAVE_DARWIN_ACL */
191 };
192 #endif  /* !HAVE_SUN_ACL || HAVE_SUN_NFS4_ACL */
193
194 #if HAVE_NFS4_ACL
195 /*
196  * Translate system NFSv4 inheritance flags into libarchive internal structure
197  */
198 static const struct {
199         const int archive_inherit;
200         const int platform_inherit;
201 } acl_inherit_map[] = {
202 #if HAVE_SUN_NFS4_ACL   /* Solaris NFSv4 inheritance flags */
203         {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACE_FILE_INHERIT_ACE},
204         {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACE_DIRECTORY_INHERIT_ACE},
205         {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACE_NO_PROPAGATE_INHERIT_ACE},
206         {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACE_INHERIT_ONLY_ACE},
207         {ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, ACE_SUCCESSFUL_ACCESS_ACE_FLAG},
208         {ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, ACE_FAILED_ACCESS_ACE_FLAG},
209 #ifdef ACE_INHERITED_ACE
210         {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACE_INHERITED_ACE}
211 #endif
212 #elif HAVE_DARWIN_ACL   /* MacOS NFSv4 inheritance flags */
213         {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACL_ENTRY_INHERITED},
214         {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT},
215         {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT},
216         {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_LIMIT_INHERIT},
217         {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_ONLY_INHERIT}
218 #else   /* FreeBSD NFSv4 ACL inheritance flags */
219         {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT},
220         {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT},
221         {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_NO_PROPAGATE_INHERIT},
222         {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_INHERIT_ONLY},
223         {ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, ACL_ENTRY_SUCCESSFUL_ACCESS},
224         {ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, ACL_ENTRY_FAILED_ACCESS},
225         {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACL_ENTRY_INHERITED}
226 #endif  /* !HAVE_SUN_NFS4_ACL && !HAVE_DARWIN_ACL */
227 };
228 #endif  /* HAVE_NFS4_ACL */
229
230 static int
231 set_acl(struct archive *a, int fd, const char *name,
232     struct archive_acl *abstract_acl,
233 #if !HAVE_SUN_ACL
234     acl_type_t acl_type,
235 #endif
236     int ae_requested_type, const char *tname)
237 {
238 #if HAVE_SUN_ACL
239         aclent_t         *aclent;
240 #if HAVE_SUN_NFS4_ACL
241         ace_t            *ace;
242 #endif
243         int              cmd, e, r;
244         void             *aclp;
245 #else
246         acl_t            acl;
247         acl_entry_t      acl_entry;
248         acl_permset_t    acl_permset;
249 #if HAVE_FREEBSD_NFS4_ACL || HAVE_DARWIN_ACL
250         acl_flagset_t    acl_flagset;
251 #endif
252 #endif  /* HAVE_SUN_ACL */
253 #if HAVE_FREEBSD_NFS4_ACL
254         int             r;
255 #endif
256         int              ret;
257         int              ae_type, ae_permset, ae_tag, ae_id;
258 #if HAVE_DARWIN_ACL
259         uuid_t          ae_uuid;
260 #endif
261         uid_t            ae_uid;
262         gid_t            ae_gid;
263         const char      *ae_name;
264         int              entries;
265         int              i;
266
267         ret = ARCHIVE_OK;
268         entries = archive_acl_reset(abstract_acl, ae_requested_type);
269         if (entries == 0)
270                 return (ARCHIVE_OK);
271
272 #if HAVE_SUN_ACL
273         switch (ae_requested_type) {
274         case ARCHIVE_ENTRY_ACL_TYPE_POSIX1E:
275                 cmd = SETACL;
276                 aclp = malloc(entries * sizeof(aclent_t));
277                 break;
278 #if HAVE_SUN_NFS4_ACL
279         case ARCHIVE_ENTRY_ACL_TYPE_NFS4:
280                 cmd = ACE_SETACL;
281                 aclp = malloc(entries * sizeof(ace_t));
282                 break;
283 #endif
284         default:
285                 errno = ENOENT;
286                 archive_set_error(a, errno, "Invalid ACL type");
287                 return (ARCHIVE_FAILED);
288         }
289
290         if (aclp == NULL) {
291                 archive_set_error(a, errno,
292                     "Can't allocate memory for acl buffer");
293                 return (ARCHIVE_FAILED);
294         }
295 #else   /* !HAVE_SUN_ACL */
296         acl = acl_init(entries);
297         if (acl == (acl_t)NULL) {
298                 archive_set_error(a, errno,
299                     "Failed to initialize ACL working storage");
300                 return (ARCHIVE_FAILED);
301         }
302 #endif  /* !HAVE_SUN_ACL */
303 #if HAVE_SUN_ACL
304         e = 0;
305 #endif
306         while (archive_acl_next(a, abstract_acl, ae_requested_type, &ae_type,
307                    &ae_permset, &ae_tag, &ae_id, &ae_name) == ARCHIVE_OK) {
308 #if HAVE_SUN_ACL
309                 aclent = NULL;
310 #if HAVE_SUN_NFS4_ACL
311                 ace = NULL;
312 #endif
313                 if (cmd == SETACL) {
314                         aclent = &((aclent_t *)aclp)[e];
315                         aclent->a_id = -1;
316                         aclent->a_type = 0;
317                         aclent->a_perm = 0;
318                 }
319 #if HAVE_SUN_NFS4_ACL
320                 else {  /* cmd == ACE_SETACL */
321                         ace = &((ace_t *)aclp)[e];
322                         ace->a_who = -1;
323                         ace->a_access_mask = 0;
324                         ace->a_flags = 0;
325                 }
326 #endif  /* HAVE_SUN_NFS4_ACL */
327 #else   /* !HAVE_SUN_ACL  */
328 #if HAVE_DARWIN_ACL
329                 /*
330                  * Mac OS doesn't support NFSv4 ACLs for
331                  * owner@, group@ and everyone@.
332                  * We skip any of these ACLs found.
333                  */
334                 if (ae_tag == ARCHIVE_ENTRY_ACL_USER_OBJ ||
335                     ae_tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ ||
336                     ae_tag == ARCHIVE_ENTRY_ACL_EVERYONE)
337                         continue;
338 #endif
339                 if (acl_create_entry(&acl, &acl_entry) != 0) {
340                         archive_set_error(a, errno,
341                             "Failed to create a new ACL entry");
342                         ret = ARCHIVE_FAILED;
343                         goto exit_free;
344                 }
345 #endif  /* !HAVE_SUN_ACL */
346 #if HAVE_DARWIN_ACL
347                 switch (ae_type) {
348                 case ARCHIVE_ENTRY_ACL_TYPE_ALLOW:
349                         acl_set_tag_type(acl_entry, ACL_EXTENDED_ALLOW);
350                         break;
351                 case ARCHIVE_ENTRY_ACL_TYPE_DENY:
352                         acl_set_tag_type(acl_entry, ACL_EXTENDED_DENY);
353                         break;
354                 default:
355                         /* We don't support any other types on MacOS */
356                         continue;
357                 }
358 #endif
359                 switch (ae_tag) {
360 #if HAVE_SUN_ACL
361                 case ARCHIVE_ENTRY_ACL_USER:
362                         ae_uid = archive_write_disk_uid(a, ae_name, ae_id);
363                         if (aclent != NULL) {
364                                 aclent->a_id = ae_uid;
365                                 aclent->a_type |= USER;
366                         }
367 #if HAVE_SUN_NFS4_ACL
368                         else {
369                                 ace->a_who = ae_uid;
370                         }
371 #endif
372                         break;
373                 case ARCHIVE_ENTRY_ACL_GROUP:
374                         ae_gid = archive_write_disk_gid(a, ae_name, ae_id);
375                         if (aclent != NULL) {
376                                 aclent->a_id = ae_gid;
377                                 aclent->a_type |= GROUP;
378                         }
379 #if HAVE_SUN_NFS4_ACL
380                         else {
381                                 ace->a_who = ae_gid;
382                                 ace->a_flags |= ACE_IDENTIFIER_GROUP;
383                         }
384 #endif
385                         break;
386                 case ARCHIVE_ENTRY_ACL_USER_OBJ:
387                         if (aclent != NULL)
388                                 aclent->a_type |= USER_OBJ;
389 #if HAVE_SUN_NFS4_ACL
390                         else {
391                                 ace->a_flags |= ACE_OWNER;
392                         }
393 #endif
394                         break;
395                 case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
396                         if (aclent != NULL)
397                                 aclent->a_type |= GROUP_OBJ;
398 #if HAVE_SUN_NFS4_ACL
399                         else {
400                                 ace->a_flags |= ACE_GROUP;
401                                 ace->a_flags |= ACE_IDENTIFIER_GROUP;
402                         }
403
404 #endif
405                         break;
406                 case ARCHIVE_ENTRY_ACL_MASK:
407                         if (aclent != NULL)
408                                 aclent->a_type |= CLASS_OBJ;
409                         break;
410                 case ARCHIVE_ENTRY_ACL_OTHER:
411                         if (aclent != NULL)
412                                 aclent->a_type |= OTHER_OBJ;
413                         break;
414 #if HAVE_SUN_NFS4_ACL
415                 case ARCHIVE_ENTRY_ACL_EVERYONE:
416                         if (ace != NULL)
417                                 ace->a_flags |= ACE_EVERYONE;
418                         break;
419 #endif
420 #else   /* !HAVE_SUN_ACL */
421                 case ARCHIVE_ENTRY_ACL_USER:
422                         ae_uid = archive_write_disk_uid(a, ae_name, ae_id);
423 #if !HAVE_DARWIN_ACL    /* FreeBSD, Linux */
424                         acl_set_tag_type(acl_entry, ACL_USER);
425                         acl_set_qualifier(acl_entry, &ae_uid);
426 #else   /* MacOS */
427                         if (mbr_identifier_to_uuid(ID_TYPE_UID, &ae_uid,
428                             sizeof(uid_t), ae_uuid) != 0)
429                                 continue;
430                         if (acl_set_qualifier(acl_entry, &ae_uuid) != 0)
431                                 continue;
432 #endif  /* HAVE_DARWIN_ACL */
433                         break;
434                 case ARCHIVE_ENTRY_ACL_GROUP:
435                         ae_gid = archive_write_disk_gid(a, ae_name, ae_id);
436 #if !HAVE_DARWIN_ACL    /* FreeBSD, Linux */
437                         acl_set_tag_type(acl_entry, ACL_GROUP);
438                         acl_set_qualifier(acl_entry, &ae_gid);
439 #else   /* MacOS */
440                         if (mbr_identifier_to_uuid(ID_TYPE_GID, &ae_gid,
441                             sizeof(gid_t), ae_uuid) != 0)
442                                 continue;
443                         if (acl_set_qualifier(acl_entry, &ae_uuid) != 0)
444                                 continue;
445 #endif  /* HAVE_DARWIN_ACL */
446                         break;
447 #if !HAVE_DARWIN_ACL    /* FreeBSD, Linux */
448                 case ARCHIVE_ENTRY_ACL_USER_OBJ:
449                         acl_set_tag_type(acl_entry, ACL_USER_OBJ);
450                         break;
451                 case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
452                         acl_set_tag_type(acl_entry, ACL_GROUP_OBJ);
453                         break;
454                 case ARCHIVE_ENTRY_ACL_MASK:
455                         acl_set_tag_type(acl_entry, ACL_MASK);
456                         break;
457                 case ARCHIVE_ENTRY_ACL_OTHER:
458                         acl_set_tag_type(acl_entry, ACL_OTHER);
459                         break;
460 #if HAVE_FREEBSD_NFS4_ACL       /* FreeBSD only */
461                 case ARCHIVE_ENTRY_ACL_EVERYONE:
462                         acl_set_tag_type(acl_entry, ACL_EVERYONE);
463                         break;
464 #endif
465 #endif  /* !HAVE_DARWIN_ACL */
466 #endif  /* !HAVE_SUN_ACL */
467                 default:
468                         archive_set_error(a, ARCHIVE_ERRNO_MISC,
469                             "Unknown ACL tag");
470                         ret = ARCHIVE_FAILED;
471                         goto exit_free;
472                 }
473
474 #if HAVE_FREEBSD_NFS4_ACL || HAVE_SUN_ACL
475                 r = 0;
476                 switch (ae_type) {
477 #if HAVE_SUN_ACL
478 #if HAVE_SUN_NFS4_ACL
479                 case ARCHIVE_ENTRY_ACL_TYPE_ALLOW:
480                         if (ace != NULL)
481                                 ace->a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
482                         else
483                                 r = -1;
484                         break;
485                 case ARCHIVE_ENTRY_ACL_TYPE_DENY:
486                         if (ace != NULL)
487                                 ace->a_type = ACE_ACCESS_DENIED_ACE_TYPE;
488                         else
489                                 r = -1;
490                         break;
491                 case ARCHIVE_ENTRY_ACL_TYPE_AUDIT:
492                         if (ace != NULL)
493                                 ace->a_type = ACE_SYSTEM_AUDIT_ACE_TYPE;
494                         else
495                                 r = -1;
496                         break;
497                 case ARCHIVE_ENTRY_ACL_TYPE_ALARM:
498                         if (ace != NULL)
499                                 ace->a_type = ACE_SYSTEM_ALARM_ACE_TYPE;
500                         else
501                                 r = -1;
502                         break;
503 #endif
504                 case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:
505                         if (aclent == NULL)
506                                 r = -1;
507                         break;
508                 case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:
509                         if (aclent != NULL)
510                                 aclent->a_type |= ACL_DEFAULT;
511                         else
512                                 r = -1;
513                         break;
514 #else   /* !HAVE_SUN_ACL */
515                 case ARCHIVE_ENTRY_ACL_TYPE_ALLOW:
516                         r = acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_ALLOW);
517                         break;
518                 case ARCHIVE_ENTRY_ACL_TYPE_DENY:
519                         r = acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_DENY);
520                         break;
521                 case ARCHIVE_ENTRY_ACL_TYPE_AUDIT:
522                         r = acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_AUDIT);
523                         break;
524                 case ARCHIVE_ENTRY_ACL_TYPE_ALARM:
525                         r = acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_ALARM);
526                         break;
527                 case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:
528                 case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:
529                         // These don't translate directly into the system ACL.
530                         break;
531 #endif  /* !HAVE_SUN_ACL */
532                 default:
533                         archive_set_error(a, ARCHIVE_ERRNO_MISC,
534                             "Unsupported ACL entry type");
535                         ret = ARCHIVE_FAILED;
536                         goto exit_free;
537                 }
538
539                 if (r != 0) {
540 #if HAVE_SUN_ACL
541                         errno = EINVAL;
542 #endif
543                         archive_set_error(a, errno,
544                             "Failed to set ACL entry type");
545                         ret = ARCHIVE_FAILED;
546                         goto exit_free;
547                 }
548 #endif  /* HAVE_FREEBSD_NFS4_ACL || HAVE_SUN_ACL */
549
550 #if HAVE_SUN_ACL
551                 if (aclent != NULL) {
552                         if (ae_permset & ARCHIVE_ENTRY_ACL_EXECUTE)
553                                 aclent->a_perm |= 1;
554                         if (ae_permset & ARCHIVE_ENTRY_ACL_WRITE)
555                                 aclent->a_perm |= 2;
556                         if (ae_permset & ARCHIVE_ENTRY_ACL_READ)
557                                 aclent->a_perm |= 4;
558                 }
559 #if HAVE_SUN_NFS4_ACL
560                 else /* falls through to for statement below, ace != NULL */
561 #endif
562 #else
563                 if (acl_get_permset(acl_entry, &acl_permset) != 0) {
564                         archive_set_error(a, errno,
565                             "Failed to get ACL permission set");
566                         ret = ARCHIVE_FAILED;
567                         goto exit_free;
568                 }
569                 if (acl_clear_perms(acl_permset) != 0) {
570                         archive_set_error(a, errno,
571                             "Failed to clear ACL permissions");
572                         ret = ARCHIVE_FAILED;
573                         goto exit_free;
574                 }
575 #endif  /* !HAVE_SUN_ACL */
576 #if HAVE_POSIX_ACL || HAVE_NFS4_ACL
577                 for (i = 0; i < (int)(sizeof(acl_perm_map) / sizeof(acl_perm_map[0])); ++i) {
578                         if (ae_permset & acl_perm_map[i].archive_perm) {
579 #if HAVE_SUN_ACL
580                                 ace->a_access_mask |=
581                                     acl_perm_map[i].platform_perm;
582 #else
583                                 if (acl_add_perm(acl_permset,
584                                     acl_perm_map[i].platform_perm) != 0) {
585                                         archive_set_error(a, errno,
586                                             "Failed to add ACL permission");
587                                         ret = ARCHIVE_FAILED;
588                                         goto exit_free;
589                                 }
590 #endif
591                         }
592                 }
593 #endif /* HAVE_POSIX_ACL || HAVE_NFS4_ACL */
594
595 #if HAVE_NFS4_ACL
596 #if HAVE_SUN_NFS4_ACL
597                 if (ace != NULL)
598 #elif HAVE_DARWIN_ACL
599                 if (acl_type == ACL_TYPE_EXTENDED)
600 #else   /* FreeBSD */
601                 if (acl_type == ACL_TYPE_NFS4)
602 #endif
603                 {
604 #if HAVE_POSIX_ACL || HAVE_DARWIN_ACL
605                         /*
606                          * acl_get_flagset_np() fails with non-NFSv4 ACLs
607                          */
608                         if (acl_get_flagset_np(acl_entry, &acl_flagset) != 0) {
609                                 archive_set_error(a, errno,
610                                     "Failed to get flagset from an NFSv4 ACL entry");
611                                 ret = ARCHIVE_FAILED;
612                                 goto exit_free;
613                         }
614                         if (acl_clear_flags_np(acl_flagset) != 0) {
615                                 archive_set_error(a, errno,
616                                     "Failed to clear flags from an NFSv4 ACL flagset");
617                                 ret = ARCHIVE_FAILED;
618                                 goto exit_free;
619                         }
620 #endif /* HAVE_POSIX_ACL || HAVE_DARWIN_ACL */
621                         for (i = 0; i < (int)(sizeof(acl_inherit_map) /sizeof(acl_inherit_map[0])); ++i) {
622                                 if (ae_permset & acl_inherit_map[i].archive_inherit) {
623 #if HAVE_SUN_ACL
624                                         ace->a_flags |=
625                                             acl_inherit_map[i].platform_inherit;
626 #else   /* !HAVE_SUN_ACL */
627                                         if (acl_add_flag_np(acl_flagset,
628                                                         acl_inherit_map[i].platform_inherit) != 0) {
629                                                 archive_set_error(a, errno,
630                                                     "Failed to add flag to NFSv4 ACL flagset");
631                                                 ret = ARCHIVE_FAILED;
632                                                 goto exit_free;
633                                         }
634 #endif  /* HAVE_SUN_ACL */
635                                 }
636                         }
637                 }
638 #endif  /* HAVE_NFS4_ACL */
639 #if HAVE_SUN_ACL
640         e++;
641 #endif
642         }
643
644 #if HAVE_ACL_SET_FD_NP || HAVE_ACL_SET_FD || HAVE_SUN_ACL
645         /* Try restoring the ACL through 'fd' if we can. */
646 #if HAVE_SUN_ACL || HAVE_ACL_SET_FD_NP
647         if (fd >= 0)
648 #else   /* !HAVE_SUN_ACL && !HAVE_ACL_SET_FD_NP */
649         if (fd >= 0 && acl_type == ACL_TYPE_ACCESS)
650 #endif
651         {
652 #if HAVE_SUN_ACL
653                 if (facl(fd, cmd, entries, aclp) == 0)
654 #elif HAVE_ACL_SET_FD_NP
655                 if (acl_set_fd_np(fd, acl, acl_type) == 0)
656 #else   /* !HAVE_SUN_ACL && !HAVE_ACL_SET_FD_NP */
657                 if (acl_set_fd(fd, acl) == 0)
658 #endif
659                         ret = ARCHIVE_OK;
660                 else {
661                         if (errno == EOPNOTSUPP) {
662                                 /* Filesystem doesn't support ACLs */
663                                 ret = ARCHIVE_OK;
664                         } else {
665                                 archive_set_error(a, errno,
666                                     "Failed to set %s acl on fd", tname);
667                         }
668                 }
669         } else
670 #endif  /* HAVE_ACL_SET_FD_NP || HAVE_ACL_SET_FD || HAVE_SUN_ACL */
671 #if HAVE_SUN_ACL
672         if (acl(name, cmd, entries, aclp) != 0)
673 #elif HAVE_ACL_SET_LINK_NP
674         if (acl_set_link_np(name, acl_type, acl) != 0)
675 #else
676         /* TODO: Skip this if 'name' is a symlink. */
677         if (acl_set_file(name, acl_type, acl) != 0)
678 #endif
679         {
680                 if (errno == EOPNOTSUPP) {
681                         /* Filesystem doesn't support ACLs */
682                         ret = ARCHIVE_OK;
683                 } else {
684                         archive_set_error(a, errno, "Failed to set %s acl",
685                             tname);
686                         ret = ARCHIVE_WARN;
687                 }
688         }
689 exit_free:
690 #if HAVE_SUN_ACL
691         free(aclp);
692 #else
693         acl_free(acl);
694 #endif
695         return (ret);
696 }
697 #endif  /* HAVE_POSIX_ACL || HAVE_NFS4_ACL */