1/*
2 * Copyright 2016 Chris Torek <torek@ixsystems.com>
3 * All rights reserved
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted providing that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
22 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
23 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <assert.h>
28#include <stdlib.h>
29#include <string.h>
30#include <errno.h>
31#include <sys/types.h>
32#include <sys/acl.h>
33#include <sys/stat.h>
34
35#include "lib9p.h"
36#include "lib9p_impl.h"
37#include "genacl.h"
38#include "fid.h"
39#include "log.h"
40
41typedef int econvertfn(acl_entry_t, struct l9p_ace *);
42
43#ifndef __APPLE__
44static struct l9p_acl *l9p_new_acl(uint32_t acetype, uint32_t aceasize);
45static struct l9p_acl *l9p_growacl(struct l9p_acl *acl, uint32_t aceasize);
46static int l9p_count_aces(acl_t sysacl);
47static struct l9p_acl *l9p_sysacl_to_acl(int, acl_t, econvertfn *);
48#endif
49static bool l9p_ingroup(gid_t tid, gid_t gid, gid_t *gids, size_t ngids);
50static int l9p_check_aces(int32_t mask, struct l9p_acl *acl, struct stat *st,
51    uid_t uid, gid_t gid, gid_t *gids, size_t ngids);
52
53void
54l9p_acl_free(struct l9p_acl *acl)
55{
56
57	free(acl);
58}
59
60/*
61 * Is the given group ID tid (test-id) any of the gid's in agids?
62 */
63static bool
64l9p_ingroup(gid_t tid, gid_t gid, gid_t *gids, size_t ngids)
65{
66	size_t i;
67
68	if (tid == gid)
69		return (true);
70	for (i = 0; i < ngids; i++)
71		if (tid == gids[i])
72			return (true);
73	return (false);
74}
75
76/* #define ACE_DEBUG */
77
78/*
79 * Note that NFSv4 tests are done on a "first match" basis.
80 * That is, we check each ACE sequentially until we run out
81 * of ACEs, or find something explicitly denied (DENIED!),
82 * or have cleared out all our attempt-something bits.  Once
83 * we come across an ALLOW entry for the bits we're trying,
84 * we clear those from the bits we're still looking for, in
85 * the order they appear.
86 *
87 * The result is either "definitely allowed" (we cleared
88 * all the bits), "definitely denied" (we hit a deny with
89 * some or all of the bits), or "unspecified".  We
90 * represent these three states as +1 (positive = yes = allow),
91 * -1 (negative = no = denied), or 0 (no strong answer).
92 *
93 * For our caller's convenience, if we are called with a
94 * mask of 0, we return 0 (no answer).
95 */
96static int
97l9p_check_aces(int32_t mask, struct l9p_acl *acl, struct stat *st,
98    uid_t uid, gid_t gid, gid_t *gids, size_t ngids)
99{
100	uint32_t i;
101	struct l9p_ace *ace;
102#ifdef ACE_DEBUG
103	const char *acetype, *allowdeny;
104	bool show_tid;
105#endif
106	bool match;
107	uid_t tid;
108
109	if (mask == 0)
110		return (0);
111
112	for (i = 0; mask != 0 && i < acl->acl_nace; i++) {
113		ace = &acl->acl_aces[i];
114		switch (ace->ace_type) {
115		case L9P_ACET_ACCESS_ALLOWED:
116		case L9P_ACET_ACCESS_DENIED:
117			break;
118		default:
119			/* audit, alarm - ignore */
120			continue;
121		}
122#ifdef ACE_DEBUG
123		show_tid = false;
124#endif
125		if (ace->ace_flags & L9P_ACEF_OWNER) {
126#ifdef ACE_DEBUG
127			acetype = "OWNER@";
128#endif
129			match = st->st_uid == uid;
130		} else if (ace->ace_flags & L9P_ACEF_GROUP) {
131#ifdef ACE_DEBUG
132			acetype = "GROUP@";
133#endif
134			match = l9p_ingroup(st->st_gid, gid, gids, ngids);
135		} else if (ace->ace_flags & L9P_ACEF_EVERYONE) {
136#ifdef ACE_DEBUG
137			acetype = "EVERYONE@";
138#endif
139			match = true;
140		} else {
141			if (ace->ace_idsize != sizeof(tid))
142				continue;
143#ifdef ACE_DEBUG
144			show_tid = true;
145#endif
146			memcpy(&tid, &ace->ace_idbytes, sizeof(tid));
147			if (ace->ace_flags & L9P_ACEF_IDENTIFIER_GROUP) {
148#ifdef ACE_DEBUG
149				acetype = "group";
150#endif
151				match = l9p_ingroup(tid, gid, gids, ngids);
152			} else {
153#ifdef ACE_DEBUG
154				acetype = "user";
155#endif
156				match = tid == uid;
157			}
158		}
159		/*
160		 * If this ACE applies to us, check remaining bits.
161		 * If any of those bits also apply, check the type:
162		 * DENY means "stop now", ALLOW means allow these bits
163		 * and keep checking.
164		 */
165#ifdef ACE_DEBUG
166		allowdeny = ace->ace_type == L9P_ACET_ACCESS_DENIED ?
167		    "deny" : "allow";
168#endif
169		if (match && (ace->ace_mask & (uint32_t)mask) != 0) {
170#ifdef ACE_DEBUG
171			if (show_tid)
172				L9P_LOG(L9P_DEBUG,
173				    "ACE: %s %s %d: mask 0x%x ace_mask 0x%x",
174				    allowdeny, acetype, (int)tid,
175				    (u_int)mask, (u_int)ace->ace_mask);
176			else
177				L9P_LOG(L9P_DEBUG,
178				    "ACE: %s %s: mask 0x%x ace_mask 0x%x",
179				    allowdeny, acetype,
180				    (u_int)mask, (u_int)ace->ace_mask);
181#endif
182			if (ace->ace_type == L9P_ACET_ACCESS_DENIED)
183				return (-1);
184			mask &= ~ace->ace_mask;
185#ifdef ACE_DEBUG
186			L9P_LOG(L9P_DEBUG, "clear 0x%x: now mask=0x%x",
187			    (u_int)ace->ace_mask, (u_int)mask);
188#endif
189		} else {
190#ifdef ACE_DEBUG
191			if (show_tid)
192				L9P_LOG(L9P_DEBUG,
193				    "ACE: SKIP %s %s %d: "
194				    "match %d mask 0x%x ace_mask 0x%x",
195				    allowdeny, acetype, (int)tid,
196				    (int)match, (u_int)mask,
197				    (u_int)ace->ace_mask);
198			else
199				L9P_LOG(L9P_DEBUG,
200				    "ACE: SKIP %s %s: "
201				    "match %d mask 0x%x ace_mask 0x%x",
202				    allowdeny, acetype,
203				    (int)match, (u_int)mask,
204				    (u_int)ace->ace_mask);
205#endif
206		}
207	}
208
209	/* Return 1 if access definitely granted. */
210#ifdef ACE_DEBUG
211	L9P_LOG(L9P_DEBUG, "ACE: end of ACEs, mask now 0x%x: %s",
212	    mask, mask ? "no-definitive-answer" : "ALLOW");
213#endif
214	return (mask == 0 ? 1 : 0);
215}
216
217/*
218 * Test against ACLs.
219 *
220 * The return value is normally 0 (access allowed) or EPERM
221 * (access denied), so it could just be a boolean....
222 *
223 * For "make new dir in dir" and "remove dir in dir", you must
224 * set the mask to test the directory permissions (not ADD_FILE but
225 * ADD_SUBDIRECTORY, and DELETE_CHILD).  For "make new file in dir"
226 * you must set the opmask to test file ADD_FILE.
227 *
228 * The L9P_ACE_DELETE flag means "can delete this thing"; it's not
229 * clear whether it should override the parent directory's ACL if
230 * any.  In our case it does not, but a caller may try
231 * L9P_ACE_DELETE_CHILD (separately, on its own) and then a
232 * (second, separate) L9P_ACE_DELETE, to make the permissions work
233 * as "or" instead of "and".
234 *
235 * Pass a NULL parent/pstat if they are not applicable, e.g.,
236 * for doing operations on an existing file, such as reading or
237 * writing data or attributes.  Pass in a null child/cstat if
238 * that's not applicable, such as creating a new file/dir.
239 *
240 * NB: it's probably wise to allow the owner of any file to update
241 * the ACLs of that file, but we leave that test to the caller.
242 */
243int l9p_acl_check_access(int32_t opmask, struct l9p_acl_check_args *args)
244{
245	struct l9p_acl *parent, *child;
246	struct stat *pstat, *cstat;
247	int32_t pop, cop;
248	size_t ngids;
249	uid_t uid;
250	gid_t gid, *gids;
251	int panswer, canswer;
252
253	assert(opmask != 0);
254	parent = args->aca_parent;
255	pstat = args->aca_pstat;
256	child = args->aca_child;
257	cstat = args->aca_cstat;
258	uid = args->aca_uid;
259	gid = args->aca_gid;
260	gids = args->aca_groups;
261	ngids = args->aca_ngroups;
262
263#ifdef ACE_DEBUG
264	L9P_LOG(L9P_DEBUG,
265	    "l9p_acl_check_access: opmask=0x%x uid=%ld gid=%ld ngids=%zd",
266	    (u_int)opmask, (long)uid, (long)gid, ngids);
267#endif
268	/*
269	 * If caller said "superuser semantics", check that first.
270	 * Note that we apply them regardless of ACLs.
271	 */
272	if (uid == 0 && args->aca_superuser)
273		return (0);
274
275	/*
276	 * If told to ignore ACLs and use only stat-based permissions,
277	 * discard any non-NULL ACL pointers.
278	 *
279	 * This will need some fancying up when we support POSIX ACLs.
280	 */
281	if ((args->aca_aclmode & L9P_ACM_NFS_ACL) == 0)
282		parent = child = NULL;
283
284	assert(parent == NULL || parent->acl_acetype == L9P_ACLTYPE_NFSv4);
285	assert(parent == NULL || pstat != NULL);
286	assert(child == NULL || child->acl_acetype == L9P_ACLTYPE_NFSv4);
287	assert(child == NULL || cstat != NULL);
288	assert(pstat != NULL || cstat != NULL);
289
290	/*
291	 * If the operation is UNLINK we should have either both ACLs
292	 * or no ACLs, but we won't require that here.
293	 *
294	 * If a parent ACL is supplied, it's a directory by definition.
295	 * Make sure we're allowed to do this there, whatever this is.
296	 * If a child ACL is supplied, check it too.  Note that the
297	 * DELETE permission only applies in the child though, not
298	 * in the parent, and the DELETE_CHILD only applies in the
299	 * parent.
300	 */
301	pop = cop = opmask;
302	if (parent != NULL || pstat != NULL) {
303		/*
304		 * Remove child-only bits from parent op and
305		 * parent-only bits from child op.
306		 *
307		 * L9P_ACE_DELETE is child-only.
308		 *
309		 * L9P_ACE_DELETE_CHILD is parent-only, and three data
310		 * access bits overlap with three directory access bits.
311		 * We should have child==NULL && cstat==NULL, so the
312		 * three data bits should be redundant, but it's
313		 * both trivial and safest to remove them anyway.
314		 */
315		pop &= ~L9P_ACE_DELETE;
316		cop &= ~(L9P_ACE_DELETE_CHILD | L9P_ACE_LIST_DIRECTORY |
317		    L9P_ACE_ADD_FILE | L9P_ACE_ADD_SUBDIRECTORY);
318	} else {
319		/*
320		 * Remove child-only bits from parent op.  We need
321		 * not bother since we just found we have no parent
322		 * and no pstat, and hence won't actually *use* pop.
323		 *
324		 * pop &= ~(L9P_ACE_READ_DATA | L9P_ACE_WRITE_DATA |
325		 *     L9P_ACE_APPEND_DATA);
326		 */
327	}
328	panswer = 0;
329	canswer = 0;
330	if (parent != NULL)
331		panswer = l9p_check_aces(pop, parent, pstat,
332		    uid, gid, gids, ngids);
333	if (child != NULL)
334		canswer = l9p_check_aces(cop, child, cstat,
335		    uid, gid, gids, ngids);
336
337	if (panswer || canswer) {
338		/*
339		 * Got a definitive answer from parent and/or
340		 * child ACLs.  We're not quite done yet though.
341		 */
342		if (opmask == L9P_ACOP_UNLINK) {
343			/*
344			 * For UNLINK, we can get an allow from child
345			 * and deny from parent, or vice versa.  It's
346			 * not 100% clear how to handle the two-answer
347			 * case.  ZFS says that if either says "allow",
348			 * we allow, and if both definitely say "deny",
349			 * we deny.  This makes sense, so we do that
350			 * here for all cases, even "strict".
351			 */
352			if (panswer > 0 || canswer > 0)
353				return (0);
354			if (panswer < 0 && canswer < 0)
355				return (EPERM);
356			/* non-definitive answer from one! move on */
357		} else {
358			/*
359			 * Have at least one definitive answer, and
360			 * should have only one; obey whichever
361			 * one it is.
362			 */
363			if (panswer)
364				return (panswer < 0 ? EPERM : 0);
365			return (canswer < 0 ? EPERM : 0);
366		}
367	}
368
369	/*
370	 * No definitive answer from ACLs alone.  Check for ZFS style
371	 * permissions checking and an "UNLINK" operation under ACLs.
372	 * If so, find write-and-execute permission on parent.
373	 * Note that WRITE overlaps with ADD_FILE -- that's ZFS's
374	 * way of saying "allow write to dir" -- but EXECUTE is
375	 * separate from LIST_DIRECTORY, so that's at least a little
376	 * bit cleaner.
377	 *
378	 * Note also that only a definitive yes (both bits are
379	 * explicitly allowed) results in granting unlink, and
380	 * a definitive no (at least one bit explicitly denied)
381	 * results in EPERM.  Only "no answer" moves on.
382	 */
383	if ((args->aca_aclmode & L9P_ACM_ZFS_ACL) &&
384	    opmask == L9P_ACOP_UNLINK && parent != NULL) {
385		panswer = l9p_check_aces(L9P_ACE_ADD_FILE | L9P_ACE_EXECUTE,
386		    parent, pstat, uid, gid, gids, ngids);
387		if (panswer)
388			return (panswer < 0 ? EPERM : 0);
389	}
390
391	/*
392	 * No definitive answer from ACLs.
393	 *
394	 * Try POSIX style rwx permissions if allowed.  This should
395	 * be rare, occurring mainly when caller supplied no ACLs
396	 * or set the mode to suppress them.
397	 *
398	 * The stat to check is the parent's if we don't have a child
399	 * (i.e., this is a dir op), or if the DELETE_CHILD bit is set
400	 * (i.e., this is an unlink or similar).  Otherwise it's the
401	 * child's.
402	 */
403	if (args->aca_aclmode & L9P_ACM_STAT_MODE) {
404		struct stat *st;
405		int rwx, bits;
406
407		rwx = l9p_ace_mask_to_rwx(opmask);
408		if ((st = cstat) == NULL || (opmask & L9P_ACE_DELETE_CHILD))
409			st = pstat;
410		if (uid == st->st_uid)
411			bits = (st->st_mode >> 6) & 7;
412		else if (l9p_ingroup(st->st_gid, gid, gids, ngids))
413			bits = (st->st_mode >> 3) & 7;
414		else
415			bits = st->st_mode & 7;
416		/*
417		 * If all the desired bits are set, we're OK.
418		 */
419		if ((rwx & bits) == rwx)
420			return (0);
421	}
422
423	/* all methods have failed, return EPERM */
424	return (EPERM);
425}
426
427/*
428 * Collapse fancy ACL operation mask down to simple Unix bits.
429 *
430 * Directory operations don't map that well.  However, listing
431 * a directory really does require read permission, and adding
432 * or deleting files really does require write permission, so
433 * this is probably sufficient.
434 */
435int
436l9p_ace_mask_to_rwx(int32_t opmask)
437{
438	int rwx = 0;
439
440	if (opmask &
441	    (L9P_ACE_READ_DATA | L9P_ACE_READ_NAMED_ATTRS |
442	     L9P_ACE_READ_ATTRIBUTES | L9P_ACE_READ_ACL))
443		rwx |= 4;
444	if (opmask &
445	    (L9P_ACE_WRITE_DATA | L9P_ACE_APPEND_DATA |
446	     L9P_ACE_ADD_FILE | L9P_ACE_ADD_SUBDIRECTORY |
447	     L9P_ACE_DELETE | L9P_ACE_DELETE_CHILD |
448	     L9P_ACE_WRITE_NAMED_ATTRS | L9P_ACE_WRITE_ATTRIBUTES |
449	     L9P_ACE_WRITE_ACL))
450		rwx |= 2;
451	if (opmask & L9P_ACE_EXECUTE)
452		rwx |= 1;
453	return (rwx);
454}
455
456#ifndef __APPLE__
457/*
458 * Allocate new ACL holder and ACEs.
459 */
460static struct l9p_acl *
461l9p_new_acl(uint32_t acetype, uint32_t aceasize)
462{
463	struct l9p_acl *ret;
464	size_t asize, size;
465
466	asize = aceasize * sizeof(struct l9p_ace);
467	size = sizeof(struct l9p_acl) + asize;
468	ret = malloc(size);
469	if (ret != NULL) {
470		ret->acl_acetype = acetype;
471		ret->acl_nace = 0;
472		ret->acl_aceasize = aceasize;
473	}
474	return (ret);
475}
476
477/*
478 * Expand ACL to accomodate more entries.
479 *
480 * Currently won't shrink, only grow, so it's a fast no-op until
481 * we hit the allocated size.  After that, it's best to grow in
482 * big chunks, or this will be O(n**2).
483 */
484static struct l9p_acl *
485l9p_growacl(struct l9p_acl *acl, uint32_t aceasize)
486{
487	struct l9p_acl *tmp;
488	size_t asize, size;
489
490	if (acl->acl_aceasize < aceasize) {
491		asize = aceasize * sizeof(struct l9p_ace);
492		size = sizeof(struct l9p_acl) + asize;
493		tmp = realloc(acl, size);
494		if (tmp == NULL)
495			free(acl);
496		acl = tmp;
497	}
498	return (acl);
499}
500
501/*
502 * Annoyingly, there's no POSIX-standard way to count the number
503 * of ACEs in a system ACL other than to walk through them all.
504 * This is silly, but at least 2n is still O(n), and the walk is
505 * short.  (If the system ACL mysteriously grows, we'll handle
506 * that OK via growacl(), too.)
507 */
508static int
509l9p_count_aces(acl_t sysacl)
510{
511	acl_entry_t entry;
512	uint32_t n;
513	int id;
514
515	id = ACL_FIRST_ENTRY;
516	for (n = 0; acl_get_entry(sysacl, id, &entry) == 1; n++)
517		id = ACL_NEXT_ENTRY;
518
519	return ((int)n);
520}
521
522/*
523 * Create ACL with ACEs from the given acl_t.  We use the given
524 * convert function on each ACE.
525 */
526static struct l9p_acl *
527l9p_sysacl_to_acl(int acetype, acl_t sysacl, econvertfn *convert)
528{
529	struct l9p_acl *acl;
530	acl_entry_t entry;
531	uint32_t n;
532	int error, id;
533
534	acl = l9p_new_acl((uint32_t)acetype, (uint32_t)l9p_count_aces(sysacl));
535	if (acl == NULL)
536		return (NULL);
537	id = ACL_FIRST_ENTRY;
538	for (n = 0;;) {
539		if (acl_get_entry(sysacl, id, &entry) != 1)
540			break;
541		acl = l9p_growacl(acl, n + 1);
542		if (acl == NULL)
543			return (NULL);
544		error = (*convert)(entry, &acl->acl_aces[n]);
545		id = ACL_NEXT_ENTRY;
546		if (error == 0)
547			n++;
548	}
549	acl->acl_nace = n;
550	return (acl);
551}
552#endif
553
554#if defined(HAVE_POSIX_ACLS) && 0 /* not yet */
555struct l9p_acl *
556l9p_posix_acl_to_acl(acl_t sysacl)
557{
558}
559#endif
560
561#if defined(HAVE_FREEBSD_ACLS)
562static int
563l9p_frombsdnfs4(acl_entry_t sysace, struct l9p_ace *ace)
564{
565	acl_tag_t tag;			/* e.g., USER_OBJ, GROUP, etc */
566	acl_entry_type_t entry_type;	/* e.g., allow/deny */
567	acl_permset_t absdperm;
568	acl_flagset_t absdflag;
569	acl_perm_t bsdperm;		/* e.g., READ_DATA */
570	acl_flag_t bsdflag;		/* e.g., FILE_INHERIT_ACE */
571	uint32_t flags, mask;
572	int error;
573	uid_t uid, *aid;
574
575	error = acl_get_tag_type(sysace, &tag);
576	if (error == 0)
577		error = acl_get_entry_type_np(sysace, &entry_type);
578	if (error == 0)
579		error = acl_get_flagset_np(sysace, &absdflag);
580	if (error == 0)
581		error = acl_get_permset(sysace, &absdperm);
582	if (error)
583		return (error);
584
585	flags = 0;
586	uid = 0;
587	aid = NULL;
588
589	/* move user/group/everyone + id-is-group-id into flags */
590	switch (tag) {
591	case ACL_USER_OBJ:
592		flags |= L9P_ACEF_OWNER;
593		break;
594	case ACL_GROUP_OBJ:
595		flags |= L9P_ACEF_GROUP;
596		break;
597	case ACL_EVERYONE:
598		flags |= L9P_ACEF_EVERYONE;
599		break;
600	case ACL_GROUP:
601		flags |= L9P_ACEF_IDENTIFIER_GROUP;
602		/* FALLTHROUGH */
603	case ACL_USER:
604		aid = acl_get_qualifier(sysace); /* ugh, this malloc()s */
605		if (aid == NULL)
606			return (ENOMEM);
607		uid = *(uid_t *)aid;
608		free(aid);
609		aid = &uid;
610		break;
611	default:
612		return (EINVAL);	/* can't happen */
613	}
614
615	switch (entry_type) {
616
617	case ACL_ENTRY_TYPE_ALLOW:
618		ace->ace_type = L9P_ACET_ACCESS_ALLOWED;
619		break;
620
621	case ACL_ENTRY_TYPE_DENY:
622		ace->ace_type = L9P_ACET_ACCESS_DENIED;
623		break;
624
625	case ACL_ENTRY_TYPE_AUDIT:
626		ace->ace_type = L9P_ACET_SYSTEM_AUDIT;
627		break;
628
629	case ACL_ENTRY_TYPE_ALARM:
630		ace->ace_type = L9P_ACET_SYSTEM_ALARM;
631		break;
632
633	default:
634		return (EINVAL);	/* can't happen */
635	}
636
637	/* transform remaining BSD flags to internal NFS-y form */
638	bsdflag = *absdflag;
639	if (bsdflag & ACL_ENTRY_FILE_INHERIT)
640		flags |= L9P_ACEF_FILE_INHERIT_ACE;
641	if (bsdflag & ACL_ENTRY_DIRECTORY_INHERIT)
642		flags |= L9P_ACEF_DIRECTORY_INHERIT_ACE;
643	if (bsdflag & ACL_ENTRY_NO_PROPAGATE_INHERIT)
644		flags |= L9P_ACEF_NO_PROPAGATE_INHERIT_ACE;
645	if (bsdflag & ACL_ENTRY_INHERIT_ONLY)
646		flags |= L9P_ACEF_INHERIT_ONLY_ACE;
647	if (bsdflag & ACL_ENTRY_SUCCESSFUL_ACCESS)
648		flags |= L9P_ACEF_SUCCESSFUL_ACCESS_ACE_FLAG;
649	if (bsdflag & ACL_ENTRY_FAILED_ACCESS)
650		flags |= L9P_ACEF_FAILED_ACCESS_ACE_FLAG;
651	ace->ace_flags = flags;
652
653	/*
654	 * Transform BSD permissions to ace_mask.  Note that directory
655	 * vs file bits are the same in both sets, so we don't need
656	 * to worry about that, at least.
657	 *
658	 * There seem to be no BSD equivalents for WRITE_RETENTION
659	 * and WRITE_RETENTION_HOLD.
660	 */
661	mask = 0;
662	bsdperm = *absdperm;
663	if (bsdperm & ACL_READ_DATA)
664		mask |= L9P_ACE_READ_DATA;
665	if (bsdperm & ACL_WRITE_DATA)
666		mask |= L9P_ACE_WRITE_DATA;
667	if (bsdperm & ACL_APPEND_DATA)
668		mask |= L9P_ACE_APPEND_DATA;
669	if (bsdperm & ACL_READ_NAMED_ATTRS)
670		mask |= L9P_ACE_READ_NAMED_ATTRS;
671	if (bsdperm & ACL_WRITE_NAMED_ATTRS)
672		mask |= L9P_ACE_WRITE_NAMED_ATTRS;
673	if (bsdperm & ACL_EXECUTE)
674		mask |= L9P_ACE_EXECUTE;
675	if (bsdperm & ACL_DELETE_CHILD)
676		mask |= L9P_ACE_DELETE_CHILD;
677	if (bsdperm & ACL_READ_ATTRIBUTES)
678		mask |= L9P_ACE_READ_ATTRIBUTES;
679	if (bsdperm & ACL_WRITE_ATTRIBUTES)
680		mask |= L9P_ACE_WRITE_ATTRIBUTES;
681	/* L9P_ACE_WRITE_RETENTION */
682	/* L9P_ACE_WRITE_RETENTION_HOLD */
683	/* 0x00800 */
684	if (bsdperm & ACL_DELETE)
685		mask |= L9P_ACE_DELETE;
686	if (bsdperm & ACL_READ_ACL)
687		mask |= L9P_ACE_READ_ACL;
688	if (bsdperm & ACL_WRITE_ACL)
689		mask |= L9P_ACE_WRITE_ACL;
690	if (bsdperm & ACL_WRITE_OWNER)
691		mask |= L9P_ACE_WRITE_OWNER;
692	if (bsdperm & ACL_SYNCHRONIZE)
693		mask |= L9P_ACE_SYNCHRONIZE;
694	ace->ace_mask = mask;
695
696	/* fill in variable-size user or group ID bytes */
697	if (aid == NULL)
698		ace->ace_idsize = 0;
699	else {
700		ace->ace_idsize = sizeof(uid);
701		memcpy(&ace->ace_idbytes[0], aid, sizeof(uid));
702	}
703
704	return (0);
705}
706
707struct l9p_acl *
708l9p_freebsd_nfsv4acl_to_acl(acl_t sysacl)
709{
710
711	return (l9p_sysacl_to_acl(L9P_ACLTYPE_NFSv4, sysacl, l9p_frombsdnfs4));
712}
713#endif
714
715#if defined(HAVE_DARWIN_ACLS) && 0 /* not yet */
716struct l9p_acl *
717l9p_darwin_nfsv4acl_to_acl(acl_t sysacl)
718{
719}
720#endif
721