1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Common NFSv4 ACL handling code.
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Copyright (c) 2002, 2003 The Regents of the University of Michigan.
5*4882a593Smuzhiyun * All rights reserved.
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * Marius Aamodt Eriksen <marius@umich.edu>
8*4882a593Smuzhiyun * Jeff Sedlak <jsedlak@umich.edu>
9*4882a593Smuzhiyun * J. Bruce Fields <bfields@umich.edu>
10*4882a593Smuzhiyun *
11*4882a593Smuzhiyun * Redistribution and use in source and binary forms, with or without
12*4882a593Smuzhiyun * modification, are permitted provided that the following conditions
13*4882a593Smuzhiyun * are met:
14*4882a593Smuzhiyun *
15*4882a593Smuzhiyun * 1. Redistributions of source code must retain the above copyright
16*4882a593Smuzhiyun * notice, this list of conditions and the following disclaimer.
17*4882a593Smuzhiyun * 2. Redistributions in binary form must reproduce the above copyright
18*4882a593Smuzhiyun * notice, this list of conditions and the following disclaimer in the
19*4882a593Smuzhiyun * documentation and/or other materials provided with the distribution.
20*4882a593Smuzhiyun * 3. Neither the name of the University nor the names of its
21*4882a593Smuzhiyun * contributors may be used to endorse or promote products derived
22*4882a593Smuzhiyun * from this software without specific prior written permission.
23*4882a593Smuzhiyun *
24*4882a593Smuzhiyun * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
25*4882a593Smuzhiyun * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
26*4882a593Smuzhiyun * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27*4882a593Smuzhiyun * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28*4882a593Smuzhiyun * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29*4882a593Smuzhiyun * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30*4882a593Smuzhiyun * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
31*4882a593Smuzhiyun * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
32*4882a593Smuzhiyun * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
33*4882a593Smuzhiyun * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
34*4882a593Smuzhiyun * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35*4882a593Smuzhiyun */
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun #include <linux/fs.h>
38*4882a593Smuzhiyun #include <linux/slab.h>
39*4882a593Smuzhiyun #include <linux/posix_acl.h>
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun #include "nfsfh.h"
42*4882a593Smuzhiyun #include "nfsd.h"
43*4882a593Smuzhiyun #include "acl.h"
44*4882a593Smuzhiyun #include "vfs.h"
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun #define NFS4_ACL_TYPE_DEFAULT 0x01
47*4882a593Smuzhiyun #define NFS4_ACL_DIR 0x02
48*4882a593Smuzhiyun #define NFS4_ACL_OWNER 0x04
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun /* mode bit translations: */
51*4882a593Smuzhiyun #define NFS4_READ_MODE (NFS4_ACE_READ_DATA)
52*4882a593Smuzhiyun #define NFS4_WRITE_MODE (NFS4_ACE_WRITE_DATA | NFS4_ACE_APPEND_DATA)
53*4882a593Smuzhiyun #define NFS4_EXECUTE_MODE NFS4_ACE_EXECUTE
54*4882a593Smuzhiyun #define NFS4_ANYONE_MODE (NFS4_ACE_READ_ATTRIBUTES | NFS4_ACE_READ_ACL | NFS4_ACE_SYNCHRONIZE)
55*4882a593Smuzhiyun #define NFS4_OWNER_MODE (NFS4_ACE_WRITE_ATTRIBUTES | NFS4_ACE_WRITE_ACL)
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun /* flags used to simulate posix default ACLs */
58*4882a593Smuzhiyun #define NFS4_INHERITANCE_FLAGS (NFS4_ACE_FILE_INHERIT_ACE \
59*4882a593Smuzhiyun | NFS4_ACE_DIRECTORY_INHERIT_ACE)
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun #define NFS4_SUPPORTED_FLAGS (NFS4_INHERITANCE_FLAGS \
62*4882a593Smuzhiyun | NFS4_ACE_INHERIT_ONLY_ACE \
63*4882a593Smuzhiyun | NFS4_ACE_IDENTIFIER_GROUP)
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun static u32
mask_from_posix(unsigned short perm,unsigned int flags)66*4882a593Smuzhiyun mask_from_posix(unsigned short perm, unsigned int flags)
67*4882a593Smuzhiyun {
68*4882a593Smuzhiyun int mask = NFS4_ANYONE_MODE;
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun if (flags & NFS4_ACL_OWNER)
71*4882a593Smuzhiyun mask |= NFS4_OWNER_MODE;
72*4882a593Smuzhiyun if (perm & ACL_READ)
73*4882a593Smuzhiyun mask |= NFS4_READ_MODE;
74*4882a593Smuzhiyun if (perm & ACL_WRITE)
75*4882a593Smuzhiyun mask |= NFS4_WRITE_MODE;
76*4882a593Smuzhiyun if ((perm & ACL_WRITE) && (flags & NFS4_ACL_DIR))
77*4882a593Smuzhiyun mask |= NFS4_ACE_DELETE_CHILD;
78*4882a593Smuzhiyun if (perm & ACL_EXECUTE)
79*4882a593Smuzhiyun mask |= NFS4_EXECUTE_MODE;
80*4882a593Smuzhiyun return mask;
81*4882a593Smuzhiyun }
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun static u32
deny_mask_from_posix(unsigned short perm,u32 flags)84*4882a593Smuzhiyun deny_mask_from_posix(unsigned short perm, u32 flags)
85*4882a593Smuzhiyun {
86*4882a593Smuzhiyun u32 mask = 0;
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun if (perm & ACL_READ)
89*4882a593Smuzhiyun mask |= NFS4_READ_MODE;
90*4882a593Smuzhiyun if (perm & ACL_WRITE)
91*4882a593Smuzhiyun mask |= NFS4_WRITE_MODE;
92*4882a593Smuzhiyun if ((perm & ACL_WRITE) && (flags & NFS4_ACL_DIR))
93*4882a593Smuzhiyun mask |= NFS4_ACE_DELETE_CHILD;
94*4882a593Smuzhiyun if (perm & ACL_EXECUTE)
95*4882a593Smuzhiyun mask |= NFS4_EXECUTE_MODE;
96*4882a593Smuzhiyun return mask;
97*4882a593Smuzhiyun }
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun /* XXX: modify functions to return NFS errors; they're only ever
100*4882a593Smuzhiyun * used by nfs code, after all.... */
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun /* We only map from NFSv4 to POSIX ACLs when setting ACLs, when we err on the
103*4882a593Smuzhiyun * side of being more restrictive, so the mode bit mapping below is
104*4882a593Smuzhiyun * pessimistic. An optimistic version would be needed to handle DENY's,
105*4882a593Smuzhiyun * but we expect to coalesce all ALLOWs and DENYs before mapping to mode
106*4882a593Smuzhiyun * bits. */
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun static void
low_mode_from_nfs4(u32 perm,unsigned short * mode,unsigned int flags)109*4882a593Smuzhiyun low_mode_from_nfs4(u32 perm, unsigned short *mode, unsigned int flags)
110*4882a593Smuzhiyun {
111*4882a593Smuzhiyun u32 write_mode = NFS4_WRITE_MODE;
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun if (flags & NFS4_ACL_DIR)
114*4882a593Smuzhiyun write_mode |= NFS4_ACE_DELETE_CHILD;
115*4882a593Smuzhiyun *mode = 0;
116*4882a593Smuzhiyun if ((perm & NFS4_READ_MODE) == NFS4_READ_MODE)
117*4882a593Smuzhiyun *mode |= ACL_READ;
118*4882a593Smuzhiyun if ((perm & write_mode) == write_mode)
119*4882a593Smuzhiyun *mode |= ACL_WRITE;
120*4882a593Smuzhiyun if ((perm & NFS4_EXECUTE_MODE) == NFS4_EXECUTE_MODE)
121*4882a593Smuzhiyun *mode |= ACL_EXECUTE;
122*4882a593Smuzhiyun }
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun static short ace2type(struct nfs4_ace *);
125*4882a593Smuzhiyun static void _posix_to_nfsv4_one(struct posix_acl *, struct nfs4_acl *,
126*4882a593Smuzhiyun unsigned int);
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun int
nfsd4_get_nfs4_acl(struct svc_rqst * rqstp,struct dentry * dentry,struct nfs4_acl ** acl)129*4882a593Smuzhiyun nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry,
130*4882a593Smuzhiyun struct nfs4_acl **acl)
131*4882a593Smuzhiyun {
132*4882a593Smuzhiyun struct inode *inode = d_inode(dentry);
133*4882a593Smuzhiyun int error = 0;
134*4882a593Smuzhiyun struct posix_acl *pacl = NULL, *dpacl = NULL;
135*4882a593Smuzhiyun unsigned int flags = 0;
136*4882a593Smuzhiyun int size = 0;
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun pacl = get_acl(inode, ACL_TYPE_ACCESS);
139*4882a593Smuzhiyun if (!pacl)
140*4882a593Smuzhiyun pacl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun if (IS_ERR(pacl))
143*4882a593Smuzhiyun return PTR_ERR(pacl);
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun /* allocate for worst case: one (deny, allow) pair each: */
146*4882a593Smuzhiyun size += 2 * pacl->a_count;
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun if (S_ISDIR(inode->i_mode)) {
149*4882a593Smuzhiyun flags = NFS4_ACL_DIR;
150*4882a593Smuzhiyun dpacl = get_acl(inode, ACL_TYPE_DEFAULT);
151*4882a593Smuzhiyun if (IS_ERR(dpacl)) {
152*4882a593Smuzhiyun error = PTR_ERR(dpacl);
153*4882a593Smuzhiyun goto rel_pacl;
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun if (dpacl)
157*4882a593Smuzhiyun size += 2 * dpacl->a_count;
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun *acl = kmalloc(nfs4_acl_bytes(size), GFP_KERNEL);
161*4882a593Smuzhiyun if (*acl == NULL) {
162*4882a593Smuzhiyun error = -ENOMEM;
163*4882a593Smuzhiyun goto out;
164*4882a593Smuzhiyun }
165*4882a593Smuzhiyun (*acl)->naces = 0;
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun _posix_to_nfsv4_one(pacl, *acl, flags & ~NFS4_ACL_TYPE_DEFAULT);
168*4882a593Smuzhiyun
169*4882a593Smuzhiyun if (dpacl)
170*4882a593Smuzhiyun _posix_to_nfsv4_one(dpacl, *acl, flags | NFS4_ACL_TYPE_DEFAULT);
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun out:
173*4882a593Smuzhiyun posix_acl_release(dpacl);
174*4882a593Smuzhiyun rel_pacl:
175*4882a593Smuzhiyun posix_acl_release(pacl);
176*4882a593Smuzhiyun return error;
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun struct posix_acl_summary {
180*4882a593Smuzhiyun unsigned short owner;
181*4882a593Smuzhiyun unsigned short users;
182*4882a593Smuzhiyun unsigned short group;
183*4882a593Smuzhiyun unsigned short groups;
184*4882a593Smuzhiyun unsigned short other;
185*4882a593Smuzhiyun unsigned short mask;
186*4882a593Smuzhiyun };
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun static void
summarize_posix_acl(struct posix_acl * acl,struct posix_acl_summary * pas)189*4882a593Smuzhiyun summarize_posix_acl(struct posix_acl *acl, struct posix_acl_summary *pas)
190*4882a593Smuzhiyun {
191*4882a593Smuzhiyun struct posix_acl_entry *pa, *pe;
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun /*
194*4882a593Smuzhiyun * Only pas.users and pas.groups need initialization; previous
195*4882a593Smuzhiyun * posix_acl_valid() calls ensure that the other fields will be
196*4882a593Smuzhiyun * initialized in the following loop. But, just to placate gcc:
197*4882a593Smuzhiyun */
198*4882a593Smuzhiyun memset(pas, 0, sizeof(*pas));
199*4882a593Smuzhiyun pas->mask = 07;
200*4882a593Smuzhiyun
201*4882a593Smuzhiyun pe = acl->a_entries + acl->a_count;
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun FOREACH_ACL_ENTRY(pa, acl, pe) {
204*4882a593Smuzhiyun switch (pa->e_tag) {
205*4882a593Smuzhiyun case ACL_USER_OBJ:
206*4882a593Smuzhiyun pas->owner = pa->e_perm;
207*4882a593Smuzhiyun break;
208*4882a593Smuzhiyun case ACL_GROUP_OBJ:
209*4882a593Smuzhiyun pas->group = pa->e_perm;
210*4882a593Smuzhiyun break;
211*4882a593Smuzhiyun case ACL_USER:
212*4882a593Smuzhiyun pas->users |= pa->e_perm;
213*4882a593Smuzhiyun break;
214*4882a593Smuzhiyun case ACL_GROUP:
215*4882a593Smuzhiyun pas->groups |= pa->e_perm;
216*4882a593Smuzhiyun break;
217*4882a593Smuzhiyun case ACL_OTHER:
218*4882a593Smuzhiyun pas->other = pa->e_perm;
219*4882a593Smuzhiyun break;
220*4882a593Smuzhiyun case ACL_MASK:
221*4882a593Smuzhiyun pas->mask = pa->e_perm;
222*4882a593Smuzhiyun break;
223*4882a593Smuzhiyun }
224*4882a593Smuzhiyun }
225*4882a593Smuzhiyun /* We'll only care about effective permissions: */
226*4882a593Smuzhiyun pas->users &= pas->mask;
227*4882a593Smuzhiyun pas->group &= pas->mask;
228*4882a593Smuzhiyun pas->groups &= pas->mask;
229*4882a593Smuzhiyun }
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun /* We assume the acl has been verified with posix_acl_valid. */
232*4882a593Smuzhiyun static void
_posix_to_nfsv4_one(struct posix_acl * pacl,struct nfs4_acl * acl,unsigned int flags)233*4882a593Smuzhiyun _posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl,
234*4882a593Smuzhiyun unsigned int flags)
235*4882a593Smuzhiyun {
236*4882a593Smuzhiyun struct posix_acl_entry *pa, *group_owner_entry;
237*4882a593Smuzhiyun struct nfs4_ace *ace;
238*4882a593Smuzhiyun struct posix_acl_summary pas;
239*4882a593Smuzhiyun unsigned short deny;
240*4882a593Smuzhiyun int eflag = ((flags & NFS4_ACL_TYPE_DEFAULT) ?
241*4882a593Smuzhiyun NFS4_INHERITANCE_FLAGS | NFS4_ACE_INHERIT_ONLY_ACE : 0);
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun BUG_ON(pacl->a_count < 3);
244*4882a593Smuzhiyun summarize_posix_acl(pacl, &pas);
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun pa = pacl->a_entries;
247*4882a593Smuzhiyun ace = acl->aces + acl->naces;
248*4882a593Smuzhiyun
249*4882a593Smuzhiyun /* We could deny everything not granted by the owner: */
250*4882a593Smuzhiyun deny = ~pas.owner;
251*4882a593Smuzhiyun /*
252*4882a593Smuzhiyun * but it is equivalent (and simpler) to deny only what is not
253*4882a593Smuzhiyun * granted by later entries:
254*4882a593Smuzhiyun */
255*4882a593Smuzhiyun deny &= pas.users | pas.group | pas.groups | pas.other;
256*4882a593Smuzhiyun if (deny) {
257*4882a593Smuzhiyun ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE;
258*4882a593Smuzhiyun ace->flag = eflag;
259*4882a593Smuzhiyun ace->access_mask = deny_mask_from_posix(deny, flags);
260*4882a593Smuzhiyun ace->whotype = NFS4_ACL_WHO_OWNER;
261*4882a593Smuzhiyun ace++;
262*4882a593Smuzhiyun acl->naces++;
263*4882a593Smuzhiyun }
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE;
266*4882a593Smuzhiyun ace->flag = eflag;
267*4882a593Smuzhiyun ace->access_mask = mask_from_posix(pa->e_perm, flags | NFS4_ACL_OWNER);
268*4882a593Smuzhiyun ace->whotype = NFS4_ACL_WHO_OWNER;
269*4882a593Smuzhiyun ace++;
270*4882a593Smuzhiyun acl->naces++;
271*4882a593Smuzhiyun pa++;
272*4882a593Smuzhiyun
273*4882a593Smuzhiyun while (pa->e_tag == ACL_USER) {
274*4882a593Smuzhiyun deny = ~(pa->e_perm & pas.mask);
275*4882a593Smuzhiyun deny &= pas.groups | pas.group | pas.other;
276*4882a593Smuzhiyun if (deny) {
277*4882a593Smuzhiyun ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE;
278*4882a593Smuzhiyun ace->flag = eflag;
279*4882a593Smuzhiyun ace->access_mask = deny_mask_from_posix(deny, flags);
280*4882a593Smuzhiyun ace->whotype = NFS4_ACL_WHO_NAMED;
281*4882a593Smuzhiyun ace->who_uid = pa->e_uid;
282*4882a593Smuzhiyun ace++;
283*4882a593Smuzhiyun acl->naces++;
284*4882a593Smuzhiyun }
285*4882a593Smuzhiyun ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE;
286*4882a593Smuzhiyun ace->flag = eflag;
287*4882a593Smuzhiyun ace->access_mask = mask_from_posix(pa->e_perm & pas.mask,
288*4882a593Smuzhiyun flags);
289*4882a593Smuzhiyun ace->whotype = NFS4_ACL_WHO_NAMED;
290*4882a593Smuzhiyun ace->who_uid = pa->e_uid;
291*4882a593Smuzhiyun ace++;
292*4882a593Smuzhiyun acl->naces++;
293*4882a593Smuzhiyun pa++;
294*4882a593Smuzhiyun }
295*4882a593Smuzhiyun
296*4882a593Smuzhiyun /* In the case of groups, we apply allow ACEs first, then deny ACEs,
297*4882a593Smuzhiyun * since a user can be in more than one group. */
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun /* allow ACEs */
300*4882a593Smuzhiyun
301*4882a593Smuzhiyun group_owner_entry = pa;
302*4882a593Smuzhiyun
303*4882a593Smuzhiyun ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE;
304*4882a593Smuzhiyun ace->flag = eflag;
305*4882a593Smuzhiyun ace->access_mask = mask_from_posix(pas.group, flags);
306*4882a593Smuzhiyun ace->whotype = NFS4_ACL_WHO_GROUP;
307*4882a593Smuzhiyun ace++;
308*4882a593Smuzhiyun acl->naces++;
309*4882a593Smuzhiyun pa++;
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun while (pa->e_tag == ACL_GROUP) {
312*4882a593Smuzhiyun ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE;
313*4882a593Smuzhiyun ace->flag = eflag | NFS4_ACE_IDENTIFIER_GROUP;
314*4882a593Smuzhiyun ace->access_mask = mask_from_posix(pa->e_perm & pas.mask,
315*4882a593Smuzhiyun flags);
316*4882a593Smuzhiyun ace->whotype = NFS4_ACL_WHO_NAMED;
317*4882a593Smuzhiyun ace->who_gid = pa->e_gid;
318*4882a593Smuzhiyun ace++;
319*4882a593Smuzhiyun acl->naces++;
320*4882a593Smuzhiyun pa++;
321*4882a593Smuzhiyun }
322*4882a593Smuzhiyun
323*4882a593Smuzhiyun /* deny ACEs */
324*4882a593Smuzhiyun
325*4882a593Smuzhiyun pa = group_owner_entry;
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun deny = ~pas.group & pas.other;
328*4882a593Smuzhiyun if (deny) {
329*4882a593Smuzhiyun ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE;
330*4882a593Smuzhiyun ace->flag = eflag;
331*4882a593Smuzhiyun ace->access_mask = deny_mask_from_posix(deny, flags);
332*4882a593Smuzhiyun ace->whotype = NFS4_ACL_WHO_GROUP;
333*4882a593Smuzhiyun ace++;
334*4882a593Smuzhiyun acl->naces++;
335*4882a593Smuzhiyun }
336*4882a593Smuzhiyun pa++;
337*4882a593Smuzhiyun
338*4882a593Smuzhiyun while (pa->e_tag == ACL_GROUP) {
339*4882a593Smuzhiyun deny = ~(pa->e_perm & pas.mask);
340*4882a593Smuzhiyun deny &= pas.other;
341*4882a593Smuzhiyun if (deny) {
342*4882a593Smuzhiyun ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE;
343*4882a593Smuzhiyun ace->flag = eflag | NFS4_ACE_IDENTIFIER_GROUP;
344*4882a593Smuzhiyun ace->access_mask = deny_mask_from_posix(deny, flags);
345*4882a593Smuzhiyun ace->whotype = NFS4_ACL_WHO_NAMED;
346*4882a593Smuzhiyun ace->who_gid = pa->e_gid;
347*4882a593Smuzhiyun ace++;
348*4882a593Smuzhiyun acl->naces++;
349*4882a593Smuzhiyun }
350*4882a593Smuzhiyun pa++;
351*4882a593Smuzhiyun }
352*4882a593Smuzhiyun
353*4882a593Smuzhiyun if (pa->e_tag == ACL_MASK)
354*4882a593Smuzhiyun pa++;
355*4882a593Smuzhiyun ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE;
356*4882a593Smuzhiyun ace->flag = eflag;
357*4882a593Smuzhiyun ace->access_mask = mask_from_posix(pa->e_perm, flags);
358*4882a593Smuzhiyun ace->whotype = NFS4_ACL_WHO_EVERYONE;
359*4882a593Smuzhiyun acl->naces++;
360*4882a593Smuzhiyun }
361*4882a593Smuzhiyun
362*4882a593Smuzhiyun static bool
pace_gt(struct posix_acl_entry * pace1,struct posix_acl_entry * pace2)363*4882a593Smuzhiyun pace_gt(struct posix_acl_entry *pace1, struct posix_acl_entry *pace2)
364*4882a593Smuzhiyun {
365*4882a593Smuzhiyun if (pace1->e_tag != pace2->e_tag)
366*4882a593Smuzhiyun return pace1->e_tag > pace2->e_tag;
367*4882a593Smuzhiyun if (pace1->e_tag == ACL_USER)
368*4882a593Smuzhiyun return uid_gt(pace1->e_uid, pace2->e_uid);
369*4882a593Smuzhiyun if (pace1->e_tag == ACL_GROUP)
370*4882a593Smuzhiyun return gid_gt(pace1->e_gid, pace2->e_gid);
371*4882a593Smuzhiyun return false;
372*4882a593Smuzhiyun }
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun static void
sort_pacl_range(struct posix_acl * pacl,int start,int end)375*4882a593Smuzhiyun sort_pacl_range(struct posix_acl *pacl, int start, int end) {
376*4882a593Smuzhiyun int sorted = 0, i;
377*4882a593Smuzhiyun
378*4882a593Smuzhiyun /* We just do a bubble sort; easy to do in place, and we're not
379*4882a593Smuzhiyun * expecting acl's to be long enough to justify anything more. */
380*4882a593Smuzhiyun while (!sorted) {
381*4882a593Smuzhiyun sorted = 1;
382*4882a593Smuzhiyun for (i = start; i < end; i++) {
383*4882a593Smuzhiyun if (pace_gt(&pacl->a_entries[i],
384*4882a593Smuzhiyun &pacl->a_entries[i+1])) {
385*4882a593Smuzhiyun sorted = 0;
386*4882a593Smuzhiyun swap(pacl->a_entries[i],
387*4882a593Smuzhiyun pacl->a_entries[i + 1]);
388*4882a593Smuzhiyun }
389*4882a593Smuzhiyun }
390*4882a593Smuzhiyun }
391*4882a593Smuzhiyun }
392*4882a593Smuzhiyun
393*4882a593Smuzhiyun static void
sort_pacl(struct posix_acl * pacl)394*4882a593Smuzhiyun sort_pacl(struct posix_acl *pacl)
395*4882a593Smuzhiyun {
396*4882a593Smuzhiyun /* posix_acl_valid requires that users and groups be in order
397*4882a593Smuzhiyun * by uid/gid. */
398*4882a593Smuzhiyun int i, j;
399*4882a593Smuzhiyun
400*4882a593Smuzhiyun /* no users or groups */
401*4882a593Smuzhiyun if (!pacl || pacl->a_count <= 4)
402*4882a593Smuzhiyun return;
403*4882a593Smuzhiyun
404*4882a593Smuzhiyun i = 1;
405*4882a593Smuzhiyun while (pacl->a_entries[i].e_tag == ACL_USER)
406*4882a593Smuzhiyun i++;
407*4882a593Smuzhiyun sort_pacl_range(pacl, 1, i-1);
408*4882a593Smuzhiyun
409*4882a593Smuzhiyun BUG_ON(pacl->a_entries[i].e_tag != ACL_GROUP_OBJ);
410*4882a593Smuzhiyun j = ++i;
411*4882a593Smuzhiyun while (pacl->a_entries[j].e_tag == ACL_GROUP)
412*4882a593Smuzhiyun j++;
413*4882a593Smuzhiyun sort_pacl_range(pacl, i, j-1);
414*4882a593Smuzhiyun return;
415*4882a593Smuzhiyun }
416*4882a593Smuzhiyun
417*4882a593Smuzhiyun /*
418*4882a593Smuzhiyun * While processing the NFSv4 ACE, this maintains bitmasks representing
419*4882a593Smuzhiyun * which permission bits have been allowed and which denied to a given
420*4882a593Smuzhiyun * entity: */
421*4882a593Smuzhiyun struct posix_ace_state {
422*4882a593Smuzhiyun u32 allow;
423*4882a593Smuzhiyun u32 deny;
424*4882a593Smuzhiyun };
425*4882a593Smuzhiyun
426*4882a593Smuzhiyun struct posix_user_ace_state {
427*4882a593Smuzhiyun union {
428*4882a593Smuzhiyun kuid_t uid;
429*4882a593Smuzhiyun kgid_t gid;
430*4882a593Smuzhiyun };
431*4882a593Smuzhiyun struct posix_ace_state perms;
432*4882a593Smuzhiyun };
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun struct posix_ace_state_array {
435*4882a593Smuzhiyun int n;
436*4882a593Smuzhiyun struct posix_user_ace_state aces[];
437*4882a593Smuzhiyun };
438*4882a593Smuzhiyun
439*4882a593Smuzhiyun /*
440*4882a593Smuzhiyun * While processing the NFSv4 ACE, this maintains the partial permissions
441*4882a593Smuzhiyun * calculated so far: */
442*4882a593Smuzhiyun
443*4882a593Smuzhiyun struct posix_acl_state {
444*4882a593Smuzhiyun int empty;
445*4882a593Smuzhiyun struct posix_ace_state owner;
446*4882a593Smuzhiyun struct posix_ace_state group;
447*4882a593Smuzhiyun struct posix_ace_state other;
448*4882a593Smuzhiyun struct posix_ace_state everyone;
449*4882a593Smuzhiyun struct posix_ace_state mask; /* Deny unused in this case */
450*4882a593Smuzhiyun struct posix_ace_state_array *users;
451*4882a593Smuzhiyun struct posix_ace_state_array *groups;
452*4882a593Smuzhiyun };
453*4882a593Smuzhiyun
454*4882a593Smuzhiyun static int
init_state(struct posix_acl_state * state,int cnt)455*4882a593Smuzhiyun init_state(struct posix_acl_state *state, int cnt)
456*4882a593Smuzhiyun {
457*4882a593Smuzhiyun int alloc;
458*4882a593Smuzhiyun
459*4882a593Smuzhiyun memset(state, 0, sizeof(struct posix_acl_state));
460*4882a593Smuzhiyun state->empty = 1;
461*4882a593Smuzhiyun /*
462*4882a593Smuzhiyun * In the worst case, each individual acl could be for a distinct
463*4882a593Smuzhiyun * named user or group, but we don't know which, so we allocate
464*4882a593Smuzhiyun * enough space for either:
465*4882a593Smuzhiyun */
466*4882a593Smuzhiyun alloc = sizeof(struct posix_ace_state_array)
467*4882a593Smuzhiyun + cnt*sizeof(struct posix_user_ace_state);
468*4882a593Smuzhiyun state->users = kzalloc(alloc, GFP_KERNEL);
469*4882a593Smuzhiyun if (!state->users)
470*4882a593Smuzhiyun return -ENOMEM;
471*4882a593Smuzhiyun state->groups = kzalloc(alloc, GFP_KERNEL);
472*4882a593Smuzhiyun if (!state->groups) {
473*4882a593Smuzhiyun kfree(state->users);
474*4882a593Smuzhiyun return -ENOMEM;
475*4882a593Smuzhiyun }
476*4882a593Smuzhiyun return 0;
477*4882a593Smuzhiyun }
478*4882a593Smuzhiyun
479*4882a593Smuzhiyun static void
free_state(struct posix_acl_state * state)480*4882a593Smuzhiyun free_state(struct posix_acl_state *state) {
481*4882a593Smuzhiyun kfree(state->users);
482*4882a593Smuzhiyun kfree(state->groups);
483*4882a593Smuzhiyun }
484*4882a593Smuzhiyun
add_to_mask(struct posix_acl_state * state,struct posix_ace_state * astate)485*4882a593Smuzhiyun static inline void add_to_mask(struct posix_acl_state *state, struct posix_ace_state *astate)
486*4882a593Smuzhiyun {
487*4882a593Smuzhiyun state->mask.allow |= astate->allow;
488*4882a593Smuzhiyun }
489*4882a593Smuzhiyun
490*4882a593Smuzhiyun static struct posix_acl *
posix_state_to_acl(struct posix_acl_state * state,unsigned int flags)491*4882a593Smuzhiyun posix_state_to_acl(struct posix_acl_state *state, unsigned int flags)
492*4882a593Smuzhiyun {
493*4882a593Smuzhiyun struct posix_acl_entry *pace;
494*4882a593Smuzhiyun struct posix_acl *pacl;
495*4882a593Smuzhiyun int nace;
496*4882a593Smuzhiyun int i;
497*4882a593Smuzhiyun
498*4882a593Smuzhiyun /*
499*4882a593Smuzhiyun * ACLs with no ACEs are treated differently in the inheritable
500*4882a593Smuzhiyun * and effective cases: when there are no inheritable ACEs,
501*4882a593Smuzhiyun * calls ->set_acl with a NULL ACL structure.
502*4882a593Smuzhiyun */
503*4882a593Smuzhiyun if (state->empty && (flags & NFS4_ACL_TYPE_DEFAULT))
504*4882a593Smuzhiyun return NULL;
505*4882a593Smuzhiyun
506*4882a593Smuzhiyun /*
507*4882a593Smuzhiyun * When there are no effective ACEs, the following will end
508*4882a593Smuzhiyun * up setting a 3-element effective posix ACL with all
509*4882a593Smuzhiyun * permissions zero.
510*4882a593Smuzhiyun */
511*4882a593Smuzhiyun if (!state->users->n && !state->groups->n)
512*4882a593Smuzhiyun nace = 3;
513*4882a593Smuzhiyun else /* Note we also include a MASK ACE in this case: */
514*4882a593Smuzhiyun nace = 4 + state->users->n + state->groups->n;
515*4882a593Smuzhiyun pacl = posix_acl_alloc(nace, GFP_KERNEL);
516*4882a593Smuzhiyun if (!pacl)
517*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
518*4882a593Smuzhiyun
519*4882a593Smuzhiyun pace = pacl->a_entries;
520*4882a593Smuzhiyun pace->e_tag = ACL_USER_OBJ;
521*4882a593Smuzhiyun low_mode_from_nfs4(state->owner.allow, &pace->e_perm, flags);
522*4882a593Smuzhiyun
523*4882a593Smuzhiyun for (i=0; i < state->users->n; i++) {
524*4882a593Smuzhiyun pace++;
525*4882a593Smuzhiyun pace->e_tag = ACL_USER;
526*4882a593Smuzhiyun low_mode_from_nfs4(state->users->aces[i].perms.allow,
527*4882a593Smuzhiyun &pace->e_perm, flags);
528*4882a593Smuzhiyun pace->e_uid = state->users->aces[i].uid;
529*4882a593Smuzhiyun add_to_mask(state, &state->users->aces[i].perms);
530*4882a593Smuzhiyun }
531*4882a593Smuzhiyun
532*4882a593Smuzhiyun pace++;
533*4882a593Smuzhiyun pace->e_tag = ACL_GROUP_OBJ;
534*4882a593Smuzhiyun low_mode_from_nfs4(state->group.allow, &pace->e_perm, flags);
535*4882a593Smuzhiyun add_to_mask(state, &state->group);
536*4882a593Smuzhiyun
537*4882a593Smuzhiyun for (i=0; i < state->groups->n; i++) {
538*4882a593Smuzhiyun pace++;
539*4882a593Smuzhiyun pace->e_tag = ACL_GROUP;
540*4882a593Smuzhiyun low_mode_from_nfs4(state->groups->aces[i].perms.allow,
541*4882a593Smuzhiyun &pace->e_perm, flags);
542*4882a593Smuzhiyun pace->e_gid = state->groups->aces[i].gid;
543*4882a593Smuzhiyun add_to_mask(state, &state->groups->aces[i].perms);
544*4882a593Smuzhiyun }
545*4882a593Smuzhiyun
546*4882a593Smuzhiyun if (state->users->n || state->groups->n) {
547*4882a593Smuzhiyun pace++;
548*4882a593Smuzhiyun pace->e_tag = ACL_MASK;
549*4882a593Smuzhiyun low_mode_from_nfs4(state->mask.allow, &pace->e_perm, flags);
550*4882a593Smuzhiyun }
551*4882a593Smuzhiyun
552*4882a593Smuzhiyun pace++;
553*4882a593Smuzhiyun pace->e_tag = ACL_OTHER;
554*4882a593Smuzhiyun low_mode_from_nfs4(state->other.allow, &pace->e_perm, flags);
555*4882a593Smuzhiyun
556*4882a593Smuzhiyun return pacl;
557*4882a593Smuzhiyun }
558*4882a593Smuzhiyun
allow_bits(struct posix_ace_state * astate,u32 mask)559*4882a593Smuzhiyun static inline void allow_bits(struct posix_ace_state *astate, u32 mask)
560*4882a593Smuzhiyun {
561*4882a593Smuzhiyun /* Allow all bits in the mask not already denied: */
562*4882a593Smuzhiyun astate->allow |= mask & ~astate->deny;
563*4882a593Smuzhiyun }
564*4882a593Smuzhiyun
deny_bits(struct posix_ace_state * astate,u32 mask)565*4882a593Smuzhiyun static inline void deny_bits(struct posix_ace_state *astate, u32 mask)
566*4882a593Smuzhiyun {
567*4882a593Smuzhiyun /* Deny all bits in the mask not already allowed: */
568*4882a593Smuzhiyun astate->deny |= mask & ~astate->allow;
569*4882a593Smuzhiyun }
570*4882a593Smuzhiyun
find_uid(struct posix_acl_state * state,kuid_t uid)571*4882a593Smuzhiyun static int find_uid(struct posix_acl_state *state, kuid_t uid)
572*4882a593Smuzhiyun {
573*4882a593Smuzhiyun struct posix_ace_state_array *a = state->users;
574*4882a593Smuzhiyun int i;
575*4882a593Smuzhiyun
576*4882a593Smuzhiyun for (i = 0; i < a->n; i++)
577*4882a593Smuzhiyun if (uid_eq(a->aces[i].uid, uid))
578*4882a593Smuzhiyun return i;
579*4882a593Smuzhiyun /* Not found: */
580*4882a593Smuzhiyun a->n++;
581*4882a593Smuzhiyun a->aces[i].uid = uid;
582*4882a593Smuzhiyun a->aces[i].perms.allow = state->everyone.allow;
583*4882a593Smuzhiyun a->aces[i].perms.deny = state->everyone.deny;
584*4882a593Smuzhiyun
585*4882a593Smuzhiyun return i;
586*4882a593Smuzhiyun }
587*4882a593Smuzhiyun
find_gid(struct posix_acl_state * state,kgid_t gid)588*4882a593Smuzhiyun static int find_gid(struct posix_acl_state *state, kgid_t gid)
589*4882a593Smuzhiyun {
590*4882a593Smuzhiyun struct posix_ace_state_array *a = state->groups;
591*4882a593Smuzhiyun int i;
592*4882a593Smuzhiyun
593*4882a593Smuzhiyun for (i = 0; i < a->n; i++)
594*4882a593Smuzhiyun if (gid_eq(a->aces[i].gid, gid))
595*4882a593Smuzhiyun return i;
596*4882a593Smuzhiyun /* Not found: */
597*4882a593Smuzhiyun a->n++;
598*4882a593Smuzhiyun a->aces[i].gid = gid;
599*4882a593Smuzhiyun a->aces[i].perms.allow = state->everyone.allow;
600*4882a593Smuzhiyun a->aces[i].perms.deny = state->everyone.deny;
601*4882a593Smuzhiyun
602*4882a593Smuzhiyun return i;
603*4882a593Smuzhiyun }
604*4882a593Smuzhiyun
deny_bits_array(struct posix_ace_state_array * a,u32 mask)605*4882a593Smuzhiyun static void deny_bits_array(struct posix_ace_state_array *a, u32 mask)
606*4882a593Smuzhiyun {
607*4882a593Smuzhiyun int i;
608*4882a593Smuzhiyun
609*4882a593Smuzhiyun for (i=0; i < a->n; i++)
610*4882a593Smuzhiyun deny_bits(&a->aces[i].perms, mask);
611*4882a593Smuzhiyun }
612*4882a593Smuzhiyun
allow_bits_array(struct posix_ace_state_array * a,u32 mask)613*4882a593Smuzhiyun static void allow_bits_array(struct posix_ace_state_array *a, u32 mask)
614*4882a593Smuzhiyun {
615*4882a593Smuzhiyun int i;
616*4882a593Smuzhiyun
617*4882a593Smuzhiyun for (i=0; i < a->n; i++)
618*4882a593Smuzhiyun allow_bits(&a->aces[i].perms, mask);
619*4882a593Smuzhiyun }
620*4882a593Smuzhiyun
process_one_v4_ace(struct posix_acl_state * state,struct nfs4_ace * ace)621*4882a593Smuzhiyun static void process_one_v4_ace(struct posix_acl_state *state,
622*4882a593Smuzhiyun struct nfs4_ace *ace)
623*4882a593Smuzhiyun {
624*4882a593Smuzhiyun u32 mask = ace->access_mask;
625*4882a593Smuzhiyun int i;
626*4882a593Smuzhiyun
627*4882a593Smuzhiyun state->empty = 0;
628*4882a593Smuzhiyun
629*4882a593Smuzhiyun switch (ace2type(ace)) {
630*4882a593Smuzhiyun case ACL_USER_OBJ:
631*4882a593Smuzhiyun if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) {
632*4882a593Smuzhiyun allow_bits(&state->owner, mask);
633*4882a593Smuzhiyun } else {
634*4882a593Smuzhiyun deny_bits(&state->owner, mask);
635*4882a593Smuzhiyun }
636*4882a593Smuzhiyun break;
637*4882a593Smuzhiyun case ACL_USER:
638*4882a593Smuzhiyun i = find_uid(state, ace->who_uid);
639*4882a593Smuzhiyun if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) {
640*4882a593Smuzhiyun allow_bits(&state->users->aces[i].perms, mask);
641*4882a593Smuzhiyun } else {
642*4882a593Smuzhiyun deny_bits(&state->users->aces[i].perms, mask);
643*4882a593Smuzhiyun mask = state->users->aces[i].perms.deny;
644*4882a593Smuzhiyun deny_bits(&state->owner, mask);
645*4882a593Smuzhiyun }
646*4882a593Smuzhiyun break;
647*4882a593Smuzhiyun case ACL_GROUP_OBJ:
648*4882a593Smuzhiyun if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) {
649*4882a593Smuzhiyun allow_bits(&state->group, mask);
650*4882a593Smuzhiyun } else {
651*4882a593Smuzhiyun deny_bits(&state->group, mask);
652*4882a593Smuzhiyun mask = state->group.deny;
653*4882a593Smuzhiyun deny_bits(&state->owner, mask);
654*4882a593Smuzhiyun deny_bits(&state->everyone, mask);
655*4882a593Smuzhiyun deny_bits_array(state->users, mask);
656*4882a593Smuzhiyun deny_bits_array(state->groups, mask);
657*4882a593Smuzhiyun }
658*4882a593Smuzhiyun break;
659*4882a593Smuzhiyun case ACL_GROUP:
660*4882a593Smuzhiyun i = find_gid(state, ace->who_gid);
661*4882a593Smuzhiyun if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) {
662*4882a593Smuzhiyun allow_bits(&state->groups->aces[i].perms, mask);
663*4882a593Smuzhiyun } else {
664*4882a593Smuzhiyun deny_bits(&state->groups->aces[i].perms, mask);
665*4882a593Smuzhiyun mask = state->groups->aces[i].perms.deny;
666*4882a593Smuzhiyun deny_bits(&state->owner, mask);
667*4882a593Smuzhiyun deny_bits(&state->group, mask);
668*4882a593Smuzhiyun deny_bits(&state->everyone, mask);
669*4882a593Smuzhiyun deny_bits_array(state->users, mask);
670*4882a593Smuzhiyun deny_bits_array(state->groups, mask);
671*4882a593Smuzhiyun }
672*4882a593Smuzhiyun break;
673*4882a593Smuzhiyun case ACL_OTHER:
674*4882a593Smuzhiyun if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) {
675*4882a593Smuzhiyun allow_bits(&state->owner, mask);
676*4882a593Smuzhiyun allow_bits(&state->group, mask);
677*4882a593Smuzhiyun allow_bits(&state->other, mask);
678*4882a593Smuzhiyun allow_bits(&state->everyone, mask);
679*4882a593Smuzhiyun allow_bits_array(state->users, mask);
680*4882a593Smuzhiyun allow_bits_array(state->groups, mask);
681*4882a593Smuzhiyun } else {
682*4882a593Smuzhiyun deny_bits(&state->owner, mask);
683*4882a593Smuzhiyun deny_bits(&state->group, mask);
684*4882a593Smuzhiyun deny_bits(&state->other, mask);
685*4882a593Smuzhiyun deny_bits(&state->everyone, mask);
686*4882a593Smuzhiyun deny_bits_array(state->users, mask);
687*4882a593Smuzhiyun deny_bits_array(state->groups, mask);
688*4882a593Smuzhiyun }
689*4882a593Smuzhiyun }
690*4882a593Smuzhiyun }
691*4882a593Smuzhiyun
nfs4_acl_nfsv4_to_posix(struct nfs4_acl * acl,struct posix_acl ** pacl,struct posix_acl ** dpacl,unsigned int flags)692*4882a593Smuzhiyun static int nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl,
693*4882a593Smuzhiyun struct posix_acl **pacl, struct posix_acl **dpacl,
694*4882a593Smuzhiyun unsigned int flags)
695*4882a593Smuzhiyun {
696*4882a593Smuzhiyun struct posix_acl_state effective_acl_state, default_acl_state;
697*4882a593Smuzhiyun struct nfs4_ace *ace;
698*4882a593Smuzhiyun int ret;
699*4882a593Smuzhiyun
700*4882a593Smuzhiyun ret = init_state(&effective_acl_state, acl->naces);
701*4882a593Smuzhiyun if (ret)
702*4882a593Smuzhiyun return ret;
703*4882a593Smuzhiyun ret = init_state(&default_acl_state, acl->naces);
704*4882a593Smuzhiyun if (ret)
705*4882a593Smuzhiyun goto out_estate;
706*4882a593Smuzhiyun ret = -EINVAL;
707*4882a593Smuzhiyun for (ace = acl->aces; ace < acl->aces + acl->naces; ace++) {
708*4882a593Smuzhiyun if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE &&
709*4882a593Smuzhiyun ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE)
710*4882a593Smuzhiyun goto out_dstate;
711*4882a593Smuzhiyun if (ace->flag & ~NFS4_SUPPORTED_FLAGS)
712*4882a593Smuzhiyun goto out_dstate;
713*4882a593Smuzhiyun if ((ace->flag & NFS4_INHERITANCE_FLAGS) == 0) {
714*4882a593Smuzhiyun process_one_v4_ace(&effective_acl_state, ace);
715*4882a593Smuzhiyun continue;
716*4882a593Smuzhiyun }
717*4882a593Smuzhiyun if (!(flags & NFS4_ACL_DIR))
718*4882a593Smuzhiyun goto out_dstate;
719*4882a593Smuzhiyun /*
720*4882a593Smuzhiyun * Note that when only one of FILE_INHERIT or DIRECTORY_INHERIT
721*4882a593Smuzhiyun * is set, we're effectively turning on the other. That's OK,
722*4882a593Smuzhiyun * according to rfc 3530.
723*4882a593Smuzhiyun */
724*4882a593Smuzhiyun process_one_v4_ace(&default_acl_state, ace);
725*4882a593Smuzhiyun
726*4882a593Smuzhiyun if (!(ace->flag & NFS4_ACE_INHERIT_ONLY_ACE))
727*4882a593Smuzhiyun process_one_v4_ace(&effective_acl_state, ace);
728*4882a593Smuzhiyun }
729*4882a593Smuzhiyun *pacl = posix_state_to_acl(&effective_acl_state, flags);
730*4882a593Smuzhiyun if (IS_ERR(*pacl)) {
731*4882a593Smuzhiyun ret = PTR_ERR(*pacl);
732*4882a593Smuzhiyun *pacl = NULL;
733*4882a593Smuzhiyun goto out_dstate;
734*4882a593Smuzhiyun }
735*4882a593Smuzhiyun *dpacl = posix_state_to_acl(&default_acl_state,
736*4882a593Smuzhiyun flags | NFS4_ACL_TYPE_DEFAULT);
737*4882a593Smuzhiyun if (IS_ERR(*dpacl)) {
738*4882a593Smuzhiyun ret = PTR_ERR(*dpacl);
739*4882a593Smuzhiyun *dpacl = NULL;
740*4882a593Smuzhiyun posix_acl_release(*pacl);
741*4882a593Smuzhiyun *pacl = NULL;
742*4882a593Smuzhiyun goto out_dstate;
743*4882a593Smuzhiyun }
744*4882a593Smuzhiyun sort_pacl(*pacl);
745*4882a593Smuzhiyun sort_pacl(*dpacl);
746*4882a593Smuzhiyun ret = 0;
747*4882a593Smuzhiyun out_dstate:
748*4882a593Smuzhiyun free_state(&default_acl_state);
749*4882a593Smuzhiyun out_estate:
750*4882a593Smuzhiyun free_state(&effective_acl_state);
751*4882a593Smuzhiyun return ret;
752*4882a593Smuzhiyun }
753*4882a593Smuzhiyun
754*4882a593Smuzhiyun __be32
nfsd4_set_nfs4_acl(struct svc_rqst * rqstp,struct svc_fh * fhp,struct nfs4_acl * acl)755*4882a593Smuzhiyun nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
756*4882a593Smuzhiyun struct nfs4_acl *acl)
757*4882a593Smuzhiyun {
758*4882a593Smuzhiyun __be32 error;
759*4882a593Smuzhiyun int host_error;
760*4882a593Smuzhiyun struct dentry *dentry;
761*4882a593Smuzhiyun struct inode *inode;
762*4882a593Smuzhiyun struct posix_acl *pacl = NULL, *dpacl = NULL;
763*4882a593Smuzhiyun unsigned int flags = 0;
764*4882a593Smuzhiyun
765*4882a593Smuzhiyun /* Get inode */
766*4882a593Smuzhiyun error = fh_verify(rqstp, fhp, 0, NFSD_MAY_SATTR);
767*4882a593Smuzhiyun if (error)
768*4882a593Smuzhiyun return error;
769*4882a593Smuzhiyun
770*4882a593Smuzhiyun dentry = fhp->fh_dentry;
771*4882a593Smuzhiyun inode = d_inode(dentry);
772*4882a593Smuzhiyun
773*4882a593Smuzhiyun if (S_ISDIR(inode->i_mode))
774*4882a593Smuzhiyun flags = NFS4_ACL_DIR;
775*4882a593Smuzhiyun
776*4882a593Smuzhiyun host_error = nfs4_acl_nfsv4_to_posix(acl, &pacl, &dpacl, flags);
777*4882a593Smuzhiyun if (host_error == -EINVAL)
778*4882a593Smuzhiyun return nfserr_attrnotsupp;
779*4882a593Smuzhiyun if (host_error < 0)
780*4882a593Smuzhiyun goto out_nfserr;
781*4882a593Smuzhiyun
782*4882a593Smuzhiyun fh_lock(fhp);
783*4882a593Smuzhiyun
784*4882a593Smuzhiyun host_error = set_posix_acl(inode, ACL_TYPE_ACCESS, pacl);
785*4882a593Smuzhiyun if (host_error < 0)
786*4882a593Smuzhiyun goto out_drop_lock;
787*4882a593Smuzhiyun
788*4882a593Smuzhiyun if (S_ISDIR(inode->i_mode)) {
789*4882a593Smuzhiyun host_error = set_posix_acl(inode, ACL_TYPE_DEFAULT, dpacl);
790*4882a593Smuzhiyun }
791*4882a593Smuzhiyun
792*4882a593Smuzhiyun out_drop_lock:
793*4882a593Smuzhiyun fh_unlock(fhp);
794*4882a593Smuzhiyun
795*4882a593Smuzhiyun posix_acl_release(pacl);
796*4882a593Smuzhiyun posix_acl_release(dpacl);
797*4882a593Smuzhiyun out_nfserr:
798*4882a593Smuzhiyun if (host_error == -EOPNOTSUPP)
799*4882a593Smuzhiyun return nfserr_attrnotsupp;
800*4882a593Smuzhiyun else
801*4882a593Smuzhiyun return nfserrno(host_error);
802*4882a593Smuzhiyun }
803*4882a593Smuzhiyun
804*4882a593Smuzhiyun
805*4882a593Smuzhiyun static short
ace2type(struct nfs4_ace * ace)806*4882a593Smuzhiyun ace2type(struct nfs4_ace *ace)
807*4882a593Smuzhiyun {
808*4882a593Smuzhiyun switch (ace->whotype) {
809*4882a593Smuzhiyun case NFS4_ACL_WHO_NAMED:
810*4882a593Smuzhiyun return (ace->flag & NFS4_ACE_IDENTIFIER_GROUP ?
811*4882a593Smuzhiyun ACL_GROUP : ACL_USER);
812*4882a593Smuzhiyun case NFS4_ACL_WHO_OWNER:
813*4882a593Smuzhiyun return ACL_USER_OBJ;
814*4882a593Smuzhiyun case NFS4_ACL_WHO_GROUP:
815*4882a593Smuzhiyun return ACL_GROUP_OBJ;
816*4882a593Smuzhiyun case NFS4_ACL_WHO_EVERYONE:
817*4882a593Smuzhiyun return ACL_OTHER;
818*4882a593Smuzhiyun }
819*4882a593Smuzhiyun BUG();
820*4882a593Smuzhiyun return -1;
821*4882a593Smuzhiyun }
822*4882a593Smuzhiyun
823*4882a593Smuzhiyun /*
824*4882a593Smuzhiyun * return the size of the struct nfs4_acl required to represent an acl
825*4882a593Smuzhiyun * with @entries entries.
826*4882a593Smuzhiyun */
nfs4_acl_bytes(int entries)827*4882a593Smuzhiyun int nfs4_acl_bytes(int entries)
828*4882a593Smuzhiyun {
829*4882a593Smuzhiyun return sizeof(struct nfs4_acl) + entries * sizeof(struct nfs4_ace);
830*4882a593Smuzhiyun }
831*4882a593Smuzhiyun
832*4882a593Smuzhiyun static struct {
833*4882a593Smuzhiyun char *string;
834*4882a593Smuzhiyun int stringlen;
835*4882a593Smuzhiyun int type;
836*4882a593Smuzhiyun } s2t_map[] = {
837*4882a593Smuzhiyun {
838*4882a593Smuzhiyun .string = "OWNER@",
839*4882a593Smuzhiyun .stringlen = sizeof("OWNER@") - 1,
840*4882a593Smuzhiyun .type = NFS4_ACL_WHO_OWNER,
841*4882a593Smuzhiyun },
842*4882a593Smuzhiyun {
843*4882a593Smuzhiyun .string = "GROUP@",
844*4882a593Smuzhiyun .stringlen = sizeof("GROUP@") - 1,
845*4882a593Smuzhiyun .type = NFS4_ACL_WHO_GROUP,
846*4882a593Smuzhiyun },
847*4882a593Smuzhiyun {
848*4882a593Smuzhiyun .string = "EVERYONE@",
849*4882a593Smuzhiyun .stringlen = sizeof("EVERYONE@") - 1,
850*4882a593Smuzhiyun .type = NFS4_ACL_WHO_EVERYONE,
851*4882a593Smuzhiyun },
852*4882a593Smuzhiyun };
853*4882a593Smuzhiyun
854*4882a593Smuzhiyun int
nfs4_acl_get_whotype(char * p,u32 len)855*4882a593Smuzhiyun nfs4_acl_get_whotype(char *p, u32 len)
856*4882a593Smuzhiyun {
857*4882a593Smuzhiyun int i;
858*4882a593Smuzhiyun
859*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(s2t_map); i++) {
860*4882a593Smuzhiyun if (s2t_map[i].stringlen == len &&
861*4882a593Smuzhiyun 0 == memcmp(s2t_map[i].string, p, len))
862*4882a593Smuzhiyun return s2t_map[i].type;
863*4882a593Smuzhiyun }
864*4882a593Smuzhiyun return NFS4_ACL_WHO_NAMED;
865*4882a593Smuzhiyun }
866*4882a593Smuzhiyun
nfs4_acl_write_who(struct xdr_stream * xdr,int who)867*4882a593Smuzhiyun __be32 nfs4_acl_write_who(struct xdr_stream *xdr, int who)
868*4882a593Smuzhiyun {
869*4882a593Smuzhiyun __be32 *p;
870*4882a593Smuzhiyun int i;
871*4882a593Smuzhiyun
872*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(s2t_map); i++) {
873*4882a593Smuzhiyun if (s2t_map[i].type != who)
874*4882a593Smuzhiyun continue;
875*4882a593Smuzhiyun p = xdr_reserve_space(xdr, s2t_map[i].stringlen + 4);
876*4882a593Smuzhiyun if (!p)
877*4882a593Smuzhiyun return nfserr_resource;
878*4882a593Smuzhiyun p = xdr_encode_opaque(p, s2t_map[i].string,
879*4882a593Smuzhiyun s2t_map[i].stringlen);
880*4882a593Smuzhiyun return 0;
881*4882a593Smuzhiyun }
882*4882a593Smuzhiyun WARN_ON_ONCE(1);
883*4882a593Smuzhiyun return nfserr_serverfault;
884*4882a593Smuzhiyun }
885