archive_disk_acl_freebsd.c revision 328828
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,
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	acl = acl_init(entries);
368	if (acl == (acl_t)NULL) {
369		archive_set_error(a, errno,
370		    "Failed to initialize ACL working storage");
371		return (ARCHIVE_FAILED);
372	}
373
374	while (archive_acl_next(a, abstract_acl, ae_requested_type, &ae_type,
375		   &ae_permset, &ae_tag, &ae_id, &ae_name) == ARCHIVE_OK) {
376		if (acl_create_entry(&acl, &acl_entry) != 0) {
377			archive_set_error(a, errno,
378			    "Failed to create a new ACL entry");
379			ret = ARCHIVE_FAILED;
380			goto exit_free;
381		}
382		switch (ae_tag) {
383		case ARCHIVE_ENTRY_ACL_USER:
384			ae_uid = archive_write_disk_uid(a, ae_name, ae_id);
385			acl_set_tag_type(acl_entry, ACL_USER);
386			acl_set_qualifier(acl_entry, &ae_uid);
387			break;
388		case ARCHIVE_ENTRY_ACL_GROUP:
389			ae_gid = archive_write_disk_gid(a, ae_name, ae_id);
390			acl_set_tag_type(acl_entry, ACL_GROUP);
391			acl_set_qualifier(acl_entry, &ae_gid);
392			break;
393		case ARCHIVE_ENTRY_ACL_USER_OBJ:
394			acl_set_tag_type(acl_entry, ACL_USER_OBJ);
395			break;
396		case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
397			acl_set_tag_type(acl_entry, ACL_GROUP_OBJ);
398			break;
399		case ARCHIVE_ENTRY_ACL_MASK:
400			acl_set_tag_type(acl_entry, ACL_MASK);
401			break;
402		case ARCHIVE_ENTRY_ACL_OTHER:
403			acl_set_tag_type(acl_entry, ACL_OTHER);
404			break;
405#if ARCHIVE_ACL_FREEBSD_NFS4
406		case ARCHIVE_ENTRY_ACL_EVERYONE:
407			acl_set_tag_type(acl_entry, ACL_EVERYONE);
408			break;
409#endif
410		default:
411			archive_set_error(a, ARCHIVE_ERRNO_MISC,
412			    "Unsupported ACL tag");
413			ret = ARCHIVE_FAILED;
414			goto exit_free;
415		}
416
417#if ARCHIVE_ACL_FREEBSD_NFS4
418		r = 0;
419		switch (ae_type) {
420		case ARCHIVE_ENTRY_ACL_TYPE_ALLOW:
421			r = acl_set_entry_type_np(acl_entry,
422			    ACL_ENTRY_TYPE_ALLOW);
423			break;
424		case ARCHIVE_ENTRY_ACL_TYPE_DENY:
425			r = acl_set_entry_type_np(acl_entry,
426			    ACL_ENTRY_TYPE_DENY);
427			break;
428		case ARCHIVE_ENTRY_ACL_TYPE_AUDIT:
429			r = acl_set_entry_type_np(acl_entry,
430			    ACL_ENTRY_TYPE_AUDIT);
431			break;
432		case ARCHIVE_ENTRY_ACL_TYPE_ALARM:
433			r = acl_set_entry_type_np(acl_entry,
434			    ACL_ENTRY_TYPE_ALARM);
435			break;
436		case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:
437		case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:
438			// These don't translate directly into the system ACL.
439			break;
440		default:
441			archive_set_error(a, ARCHIVE_ERRNO_MISC,
442			    "Unsupported ACL entry type");
443			ret = ARCHIVE_FAILED;
444			goto exit_free;
445		}
446
447		if (r != 0) {
448			archive_set_error(a, errno,
449			    "Failed to set ACL entry type");
450			ret = ARCHIVE_FAILED;
451			goto exit_free;
452		}
453#endif
454
455		if (acl_get_permset(acl_entry, &acl_permset) != 0) {
456			archive_set_error(a, errno,
457			    "Failed to get ACL permission set");
458			ret = ARCHIVE_FAILED;
459			goto exit_free;
460		}
461		if (acl_clear_perms(acl_permset) != 0) {
462			archive_set_error(a, errno,
463			    "Failed to clear ACL permissions");
464			ret = ARCHIVE_FAILED;
465			goto exit_free;
466		}
467#if ARCHIVE_ACL_FREEBSD_NFS4
468		if (ae_requested_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
469			perm_map_size = acl_nfs4_perm_map_size;
470			perm_map = acl_nfs4_perm_map;
471		} else {
472#endif
473			perm_map_size = acl_posix_perm_map_size;
474			perm_map = acl_posix_perm_map;
475#if ARCHIVE_ACL_FREEBSD_NFS4
476		}
477#endif
478
479		for (i = 0; i < perm_map_size; ++i) {
480			if (ae_permset & perm_map[i].a_perm) {
481				if (acl_add_perm(acl_permset,
482				    perm_map[i].p_perm) != 0) {
483					archive_set_error(a, errno,
484					    "Failed to add ACL permission");
485					ret = ARCHIVE_FAILED;
486					goto exit_free;
487				}
488			}
489		}
490
491#if ARCHIVE_ACL_FREEBSD_NFS4
492		if (ae_requested_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
493			/*
494			 * acl_get_flagset_np() fails with non-NFSv4 ACLs
495			 */
496			if (acl_get_flagset_np(acl_entry, &acl_flagset) != 0) {
497				archive_set_error(a, errno,
498				    "Failed to get flagset from an NFSv4 "
499				    "ACL entry");
500				ret = ARCHIVE_FAILED;
501				goto exit_free;
502			}
503			if (acl_clear_flags_np(acl_flagset) != 0) {
504				archive_set_error(a, errno,
505				    "Failed to clear flags from an NFSv4 "
506				    "ACL flagset");
507				ret = ARCHIVE_FAILED;
508				goto exit_free;
509			}
510			for (i = 0; i < acl_nfs4_flag_map_size; ++i) {
511				if (ae_permset & acl_nfs4_flag_map[i].a_perm) {
512					if (acl_add_flag_np(acl_flagset,
513					    acl_nfs4_flag_map[i].p_perm) != 0) {
514						archive_set_error(a, errno,
515						    "Failed to add flag to "
516						    "NFSv4 ACL flagset");
517						ret = ARCHIVE_FAILED;
518						goto exit_free;
519					}
520				}
521			}
522		}
523#endif
524	}
525
526	/* Try restoring the ACL through 'fd' if we can. */
527	if (fd >= 0) {
528		if (acl_set_fd_np(fd, acl, acl_type) == 0)
529			ret = ARCHIVE_OK;
530		else {
531			if (errno == EOPNOTSUPP) {
532				/* Filesystem doesn't support ACLs */
533				ret = ARCHIVE_OK;
534			} else {
535				archive_set_error(a, errno,
536				    "Failed to set acl on fd: %s", tname);
537				ret = ARCHIVE_WARN;
538			}
539		}
540	}
541#if HAVE_ACL_SET_LINK_NP
542	else if (acl_set_link_np(name, acl_type, acl) != 0)
543#else
544	/* FreeBSD older than 8.0 */
545	else if (acl_set_file(name, acl_type, acl) != 0)
546#endif
547	{
548		if (errno == EOPNOTSUPP) {
549			/* Filesystem doesn't support ACLs */
550			ret = ARCHIVE_OK;
551		} else {
552			archive_set_error(a, errno, "Failed to set acl: %s",
553			    tname);
554			ret = ARCHIVE_WARN;
555		}
556	}
557exit_free:
558	acl_free(acl);
559	return (ret);
560}
561
562int
563archive_read_disk_entry_setup_acls(struct archive_read_disk *a,
564    struct archive_entry *entry, int *fd)
565{
566	const char	*accpath;
567	acl_t		acl;
568	int		r;
569
570	accpath = NULL;
571
572	if (*fd < 0) {
573		accpath = archive_read_disk_entry_setup_path(a, entry, fd);
574		if (accpath == NULL)
575			return (ARCHIVE_WARN);
576	}
577
578	archive_entry_acl_clear(entry);
579
580	acl = NULL;
581
582#if ARCHIVE_ACL_FREEBSD_NFS4
583	/* Try NFSv4 ACL first. */
584	if (*fd >= 0)
585		acl = acl_get_fd_np(*fd, ACL_TYPE_NFS4);
586	else if (!a->follow_symlinks)
587		acl = acl_get_link_np(accpath, ACL_TYPE_NFS4);
588	else
589		acl = acl_get_file(accpath, ACL_TYPE_NFS4);
590
591	/* Ignore "trivial" ACLs that just mirror the file mode. */
592	if (acl != NULL && acl_is_trivial_np(acl, &r) == 0 && r == 1) {
593		acl_free(acl);
594		acl = NULL;
595		return (ARCHIVE_OK);
596	}
597
598	if (acl != NULL) {
599		r = translate_acl(a, entry, acl, ARCHIVE_ENTRY_ACL_TYPE_NFS4);
600		acl_free(acl);
601		acl = NULL;
602
603		if (r != ARCHIVE_OK) {
604			archive_set_error(&a->archive, errno,
605			    "Couldn't translate NFSv4 ACLs");
606		}
607
608		return (r);
609	}
610#endif
611
612	/* Retrieve access ACL from file. */
613	if (*fd >= 0)
614		acl = acl_get_fd_np(*fd, ACL_TYPE_ACCESS);
615#if HAVE_ACL_GET_LINK_NP
616	else if (!a->follow_symlinks)
617		acl = acl_get_link_np(accpath, ACL_TYPE_ACCESS);
618#else
619	else if ((!a->follow_symlinks)
620	    && (archive_entry_filetype(entry) == AE_IFLNK))
621		/* We can't get the ACL of a symlink, so we assume it can't
622		   have one. */
623		acl = NULL;
624#endif
625	else
626		acl = acl_get_file(accpath, ACL_TYPE_ACCESS);
627
628#if HAVE_ACL_IS_TRIVIAL_NP
629	/* Ignore "trivial" ACLs that just mirror the file mode. */
630	if (acl != NULL && acl_is_trivial_np(acl, &r) == 0 && r == 1) {
631		acl_free(acl);
632		acl = NULL;
633	}
634#endif
635
636	if (acl != NULL) {
637		r = translate_acl(a, entry, acl, ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
638		acl_free(acl);
639		acl = NULL;
640
641		if (r != ARCHIVE_OK) {
642			archive_set_error(&a->archive, errno,
643			    "Couldn't translate access ACLs");
644			return (r);
645		}
646	}
647
648	/* Only directories can have default ACLs. */
649	if (S_ISDIR(archive_entry_mode(entry))) {
650		if (*fd >= 0)
651			acl = acl_get_fd_np(*fd, ACL_TYPE_DEFAULT);
652		else
653			acl = acl_get_file(accpath, ACL_TYPE_DEFAULT);
654		if (acl != NULL) {
655			r = translate_acl(a, entry, acl,
656			    ARCHIVE_ENTRY_ACL_TYPE_DEFAULT);
657			acl_free(acl);
658			if (r != ARCHIVE_OK) {
659				archive_set_error(&a->archive, errno,
660				    "Couldn't translate default ACLs");
661				return (r);
662			}
663		}
664	}
665	return (ARCHIVE_OK);
666}
667
668int
669archive_write_disk_set_acls(struct archive *a, int fd, const char *name,
670    struct archive_acl *abstract_acl, __LA_MODE_T mode)
671{
672	int		ret = ARCHIVE_OK;
673
674	(void)mode;	/* UNUSED */
675
676	if ((archive_acl_types(abstract_acl)
677	    & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) {
678		if ((archive_acl_types(abstract_acl)
679		    & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
680			ret = set_acl(a, fd, name, abstract_acl,
681			    ARCHIVE_ENTRY_ACL_TYPE_ACCESS, "access");
682			if (ret != ARCHIVE_OK)
683				return (ret);
684		}
685		if ((archive_acl_types(abstract_acl)
686		    & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0)
687			ret = set_acl(a, fd, name, abstract_acl,
688			    ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, "default");
689
690		/* Simultaneous POSIX.1e and NFSv4 is not supported */
691		return (ret);
692	}
693#if ARCHIVE_ACL_FREEBSD_NFS4
694	else if ((archive_acl_types(abstract_acl) &
695	    ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) {
696		ret = set_acl(a, fd, name, abstract_acl,
697		    ARCHIVE_ENTRY_ACL_TYPE_NFS4, "nfs4");
698	}
699#endif
700	return (ret);
701}
702#endif	/* ARCHIVE_ACL_FREEBSD */
703