xref: /openbmc/linux/fs/nfsd/nfs2acl.c (revision e23feb16)
1 /*
2  * Process version 2 NFSACL requests.
3  *
4  * Copyright (C) 2002-2003 Andreas Gruenbacher <agruen@suse.de>
5  */
6 
7 #include "nfsd.h"
8 /* FIXME: nfsacl.h is a broken header */
9 #include <linux/nfsacl.h>
10 #include <linux/gfp.h>
11 #include "cache.h"
12 #include "xdr3.h"
13 #include "vfs.h"
14 
15 #define NFSDDBG_FACILITY		NFSDDBG_PROC
16 #define RETURN_STATUS(st)	{ resp->status = (st); return (st); }
17 
18 /*
19  * NULL call.
20  */
21 static __be32
22 nfsacld_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
23 {
24 	return nfs_ok;
25 }
26 
27 /*
28  * Get the Access and/or Default ACL of a file.
29  */
30 static __be32 nfsacld_proc_getacl(struct svc_rqst * rqstp,
31 		struct nfsd3_getaclargs *argp, struct nfsd3_getaclres *resp)
32 {
33 	svc_fh *fh;
34 	struct posix_acl *acl;
35 	__be32 nfserr = 0;
36 
37 	dprintk("nfsd: GETACL(2acl)   %s\n", SVCFH_fmt(&argp->fh));
38 
39 	fh = fh_copy(&resp->fh, &argp->fh);
40 	nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP);
41 	if (nfserr)
42 		RETURN_STATUS(nfserr);
43 
44 	if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT))
45 		RETURN_STATUS(nfserr_inval);
46 	resp->mask = argp->mask;
47 
48 	nfserr = fh_getattr(fh, &resp->stat);
49 	if (nfserr)
50 		goto fail;
51 
52 	if (resp->mask & (NFS_ACL|NFS_ACLCNT)) {
53 		acl = nfsd_get_posix_acl(fh, ACL_TYPE_ACCESS);
54 		if (IS_ERR(acl)) {
55 			int err = PTR_ERR(acl);
56 
57 			if (err == -ENODATA || err == -EOPNOTSUPP)
58 				acl = NULL;
59 			else {
60 				nfserr = nfserrno(err);
61 				goto fail;
62 			}
63 		}
64 		if (acl == NULL) {
65 			/* Solaris returns the inode's minimum ACL. */
66 
67 			struct inode *inode = fh->fh_dentry->d_inode;
68 			acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
69 		}
70 		resp->acl_access = acl;
71 	}
72 	if (resp->mask & (NFS_DFACL|NFS_DFACLCNT)) {
73 		/* Check how Solaris handles requests for the Default ACL
74 		   of a non-directory! */
75 
76 		acl = nfsd_get_posix_acl(fh, ACL_TYPE_DEFAULT);
77 		if (IS_ERR(acl)) {
78 			int err = PTR_ERR(acl);
79 
80 			if (err == -ENODATA || err == -EOPNOTSUPP)
81 				acl = NULL;
82 			else {
83 				nfserr = nfserrno(err);
84 				goto fail;
85 			}
86 		}
87 		resp->acl_default = acl;
88 	}
89 
90 	/* resp->acl_{access,default} are released in nfssvc_release_getacl. */
91 	RETURN_STATUS(0);
92 
93 fail:
94 	posix_acl_release(resp->acl_access);
95 	posix_acl_release(resp->acl_default);
96 	RETURN_STATUS(nfserr);
97 }
98 
99 /*
100  * Set the Access and/or Default ACL of a file.
101  */
102 static __be32 nfsacld_proc_setacl(struct svc_rqst * rqstp,
103 		struct nfsd3_setaclargs *argp,
104 		struct nfsd_attrstat *resp)
105 {
106 	svc_fh *fh;
107 	__be32 nfserr = 0;
108 
109 	dprintk("nfsd: SETACL(2acl)   %s\n", SVCFH_fmt(&argp->fh));
110 
111 	fh = fh_copy(&resp->fh, &argp->fh);
112 	nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_SATTR);
113 
114 	if (!nfserr) {
115 		nfserr = nfserrno( nfsd_set_posix_acl(
116 			fh, ACL_TYPE_ACCESS, argp->acl_access) );
117 	}
118 	if (!nfserr) {
119 		nfserr = nfserrno( nfsd_set_posix_acl(
120 			fh, ACL_TYPE_DEFAULT, argp->acl_default) );
121 	}
122 	if (!nfserr) {
123 		nfserr = fh_getattr(fh, &resp->stat);
124 	}
125 
126 	/* argp->acl_{access,default} may have been allocated in
127 	   nfssvc_decode_setaclargs. */
128 	posix_acl_release(argp->acl_access);
129 	posix_acl_release(argp->acl_default);
130 	return nfserr;
131 }
132 
133 /*
134  * Check file attributes
135  */
136 static __be32 nfsacld_proc_getattr(struct svc_rqst * rqstp,
137 		struct nfsd_fhandle *argp, struct nfsd_attrstat *resp)
138 {
139 	__be32 nfserr;
140 	dprintk("nfsd: GETATTR  %s\n", SVCFH_fmt(&argp->fh));
141 
142 	fh_copy(&resp->fh, &argp->fh);
143 	nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP);
144 	if (nfserr)
145 		return nfserr;
146 	nfserr = fh_getattr(&resp->fh, &resp->stat);
147 	return nfserr;
148 }
149 
150 /*
151  * Check file access
152  */
153 static __be32 nfsacld_proc_access(struct svc_rqst *rqstp, struct nfsd3_accessargs *argp,
154 		struct nfsd3_accessres *resp)
155 {
156 	__be32 nfserr;
157 
158 	dprintk("nfsd: ACCESS(2acl)   %s 0x%x\n",
159 			SVCFH_fmt(&argp->fh),
160 			argp->access);
161 
162 	fh_copy(&resp->fh, &argp->fh);
163 	resp->access = argp->access;
164 	nfserr = nfsd_access(rqstp, &resp->fh, &resp->access, NULL);
165 	if (nfserr)
166 		return nfserr;
167 	nfserr = fh_getattr(&resp->fh, &resp->stat);
168 	return nfserr;
169 }
170 
171 /*
172  * XDR decode functions
173  */
174 static int nfsaclsvc_decode_getaclargs(struct svc_rqst *rqstp, __be32 *p,
175 		struct nfsd3_getaclargs *argp)
176 {
177 	if (!(p = nfs2svc_decode_fh(p, &argp->fh)))
178 		return 0;
179 	argp->mask = ntohl(*p); p++;
180 
181 	return xdr_argsize_check(rqstp, p);
182 }
183 
184 
185 static int nfsaclsvc_decode_setaclargs(struct svc_rqst *rqstp, __be32 *p,
186 		struct nfsd3_setaclargs *argp)
187 {
188 	struct kvec *head = rqstp->rq_arg.head;
189 	unsigned int base;
190 	int n;
191 
192 	if (!(p = nfs2svc_decode_fh(p, &argp->fh)))
193 		return 0;
194 	argp->mask = ntohl(*p++);
195 	if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT) ||
196 	    !xdr_argsize_check(rqstp, p))
197 		return 0;
198 
199 	base = (char *)p - (char *)head->iov_base;
200 	n = nfsacl_decode(&rqstp->rq_arg, base, NULL,
201 			  (argp->mask & NFS_ACL) ?
202 			  &argp->acl_access : NULL);
203 	if (n > 0)
204 		n = nfsacl_decode(&rqstp->rq_arg, base + n, NULL,
205 				  (argp->mask & NFS_DFACL) ?
206 				  &argp->acl_default : NULL);
207 	return (n > 0);
208 }
209 
210 static int nfsaclsvc_decode_fhandleargs(struct svc_rqst *rqstp, __be32 *p,
211 		struct nfsd_fhandle *argp)
212 {
213 	if (!(p = nfs2svc_decode_fh(p, &argp->fh)))
214 		return 0;
215 	return xdr_argsize_check(rqstp, p);
216 }
217 
218 static int nfsaclsvc_decode_accessargs(struct svc_rqst *rqstp, __be32 *p,
219 		struct nfsd3_accessargs *argp)
220 {
221 	if (!(p = nfs2svc_decode_fh(p, &argp->fh)))
222 		return 0;
223 	argp->access = ntohl(*p++);
224 
225 	return xdr_argsize_check(rqstp, p);
226 }
227 
228 /*
229  * XDR encode functions
230  */
231 
232 /*
233  * There must be an encoding function for void results so svc_process
234  * will work properly.
235  */
236 static int nfsaclsvc_encode_voidres(struct svc_rqst *rqstp, __be32 *p, void *dummy)
237 {
238 	return xdr_ressize_check(rqstp, p);
239 }
240 
241 /* GETACL */
242 static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p,
243 		struct nfsd3_getaclres *resp)
244 {
245 	struct dentry *dentry = resp->fh.fh_dentry;
246 	struct inode *inode;
247 	struct kvec *head = rqstp->rq_res.head;
248 	unsigned int base;
249 	int n;
250 	int w;
251 
252 	/*
253 	 * Since this is version 2, the check for nfserr in
254 	 * nfsd_dispatch actually ensures the following cannot happen.
255 	 * However, it seems fragile to depend on that.
256 	 */
257 	if (dentry == NULL || dentry->d_inode == NULL)
258 		return 0;
259 	inode = dentry->d_inode;
260 
261 	p = nfs2svc_encode_fattr(rqstp, p, &resp->fh, &resp->stat);
262 	*p++ = htonl(resp->mask);
263 	if (!xdr_ressize_check(rqstp, p))
264 		return 0;
265 	base = (char *)p - (char *)head->iov_base;
266 
267 	rqstp->rq_res.page_len = w = nfsacl_size(
268 		(resp->mask & NFS_ACL)   ? resp->acl_access  : NULL,
269 		(resp->mask & NFS_DFACL) ? resp->acl_default : NULL);
270 	while (w > 0) {
271 		if (!*(rqstp->rq_next_page++))
272 			return 0;
273 		w -= PAGE_SIZE;
274 	}
275 
276 	n = nfsacl_encode(&rqstp->rq_res, base, inode,
277 			  resp->acl_access,
278 			  resp->mask & NFS_ACL, 0);
279 	if (n > 0)
280 		n = nfsacl_encode(&rqstp->rq_res, base + n, inode,
281 				  resp->acl_default,
282 				  resp->mask & NFS_DFACL,
283 				  NFS_ACL_DEFAULT);
284 	if (n <= 0)
285 		return 0;
286 	return 1;
287 }
288 
289 static int nfsaclsvc_encode_attrstatres(struct svc_rqst *rqstp, __be32 *p,
290 		struct nfsd_attrstat *resp)
291 {
292 	p = nfs2svc_encode_fattr(rqstp, p, &resp->fh, &resp->stat);
293 	return xdr_ressize_check(rqstp, p);
294 }
295 
296 /* ACCESS */
297 static int nfsaclsvc_encode_accessres(struct svc_rqst *rqstp, __be32 *p,
298 		struct nfsd3_accessres *resp)
299 {
300 	p = nfs2svc_encode_fattr(rqstp, p, &resp->fh, &resp->stat);
301 	*p++ = htonl(resp->access);
302 	return xdr_ressize_check(rqstp, p);
303 }
304 
305 /*
306  * XDR release functions
307  */
308 static int nfsaclsvc_release_getacl(struct svc_rqst *rqstp, __be32 *p,
309 		struct nfsd3_getaclres *resp)
310 {
311 	fh_put(&resp->fh);
312 	posix_acl_release(resp->acl_access);
313 	posix_acl_release(resp->acl_default);
314 	return 1;
315 }
316 
317 static int nfsaclsvc_release_attrstat(struct svc_rqst *rqstp, __be32 *p,
318 		struct nfsd_attrstat *resp)
319 {
320 	fh_put(&resp->fh);
321 	return 1;
322 }
323 
324 static int nfsaclsvc_release_access(struct svc_rqst *rqstp, __be32 *p,
325                struct nfsd3_accessres *resp)
326 {
327        fh_put(&resp->fh);
328        return 1;
329 }
330 
331 #define nfsaclsvc_decode_voidargs	NULL
332 #define nfsaclsvc_release_void		NULL
333 #define nfsd3_fhandleargs	nfsd_fhandle
334 #define nfsd3_attrstatres	nfsd_attrstat
335 #define nfsd3_voidres		nfsd3_voidargs
336 struct nfsd3_voidargs { int dummy; };
337 
338 #define PROC(name, argt, rest, relt, cache, respsize)	\
339  { (svc_procfunc) nfsacld_proc_##name,		\
340    (kxdrproc_t) nfsaclsvc_decode_##argt##args,	\
341    (kxdrproc_t) nfsaclsvc_encode_##rest##res,	\
342    (kxdrproc_t) nfsaclsvc_release_##relt,		\
343    sizeof(struct nfsd3_##argt##args),		\
344    sizeof(struct nfsd3_##rest##res),		\
345    0,						\
346    cache,					\
347    respsize,					\
348  }
349 
350 #define ST 1		/* status*/
351 #define AT 21		/* attributes */
352 #define pAT (1+AT)	/* post attributes - conditional */
353 #define ACL (1+NFS_ACL_MAX_ENTRIES*3)  /* Access Control List */
354 
355 static struct svc_procedure		nfsd_acl_procedures2[] = {
356   PROC(null,	void,		void,		void,	  RC_NOCACHE, ST),
357   PROC(getacl,	getacl,		getacl,		getacl,	  RC_NOCACHE, ST+1+2*(1+ACL)),
358   PROC(setacl,	setacl,		attrstat,	attrstat, RC_NOCACHE, ST+AT),
359   PROC(getattr, fhandle,	attrstat,	attrstat, RC_NOCACHE, ST+AT),
360   PROC(access,	access,		access,		access,   RC_NOCACHE, ST+AT+1),
361 };
362 
363 struct svc_version	nfsd_acl_version2 = {
364 		.vs_vers	= 2,
365 		.vs_nproc	= 5,
366 		.vs_proc	= nfsd_acl_procedures2,
367 		.vs_dispatch	= nfsd_dispatch,
368 		.vs_xdrsize	= NFS3_SVC_XDRSIZE,
369 		.vs_hidden	= 0,
370 };
371