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