xref: /freebsd/contrib/lib9p/genacl.c (revision 02e9120893770924227138ba49df1edb3896112a)
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 
41 typedef int econvertfn(acl_entry_t, struct l9p_ace *);
42 
43 #ifndef __APPLE__
44 static struct l9p_acl *l9p_new_acl(uint32_t acetype, uint32_t aceasize);
45 static struct l9p_acl *l9p_growacl(struct l9p_acl *acl, uint32_t aceasize);
46 static int l9p_count_aces(acl_t sysacl);
47 static struct l9p_acl *l9p_sysacl_to_acl(int, acl_t, econvertfn *);
48 #endif
49 static bool l9p_ingroup(gid_t tid, gid_t gid, gid_t *gids, size_t ngids);
50 static 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 
53 void
54 l9p_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  */
63 static bool
64 l9p_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  */
96 static int
97 l9p_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  */
243 int 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  */
435 int
436 l9p_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  */
460 static struct l9p_acl *
461 l9p_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  */
484 static struct l9p_acl *
485 l9p_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  */
508 static int
509 l9p_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  */
526 static struct l9p_acl *
527 l9p_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 */
555 struct l9p_acl *
556 l9p_posix_acl_to_acl(acl_t sysacl)
557 {
558 }
559 #endif
560 
561 #if defined(HAVE_FREEBSD_ACLS)
562 static int
563 l9p_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 
707 struct l9p_acl *
708 l9p_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 */
716 struct l9p_acl *
717 l9p_darwin_nfsv4acl_to_acl(acl_t sysacl)
718 {
719 }
720 #endif
721