xref: /OK3568_Linux_fs/kernel/fs/nfsd/nfs4acl.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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