archive_disk_acl_freebsd.c revision 370535
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
51typedef 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
56static 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
62static 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
66static 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
86static const int acl_nfs4_perm_map_size =
87    (int)(sizeof(acl_nfs4_perm_map)/sizeof(acl_nfs4_perm_map[0]));
88
89static 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
101static 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
105static int
106translate_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
320static int
321set_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	}
567exit_free:
568	acl_free(acl);
569	return (ret);
570}
571
572int
573archive_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
678int
679archive_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 */
713