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