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