Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
nfs2acl.c
Go to the documentation of this file.
1 /*
2  * Process version 2 NFSACL requests.
3  *
4  * Copyright (C) 2002-2003 Andreas Gruenbacher <[email protected]>
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 
46  resp->mask = argp->mask;
47 
48  if (resp->mask & (NFS_ACL|NFS_ACLCNT)) {
49  acl = nfsd_get_posix_acl(fh, ACL_TYPE_ACCESS);
50  if (IS_ERR(acl)) {
51  int err = PTR_ERR(acl);
52 
53  if (err == -ENODATA || err == -EOPNOTSUPP)
54  acl = NULL;
55  else {
56  nfserr = nfserrno(err);
57  goto fail;
58  }
59  }
60  if (acl == NULL) {
61  /* Solaris returns the inode's minimum ACL. */
62 
63  struct inode *inode = fh->fh_dentry->d_inode;
64  acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
65  }
66  resp->acl_access = acl;
67  }
68  if (resp->mask & (NFS_DFACL|NFS_DFACLCNT)) {
69  /* Check how Solaris handles requests for the Default ACL
70  of a non-directory! */
71 
72  acl = nfsd_get_posix_acl(fh, ACL_TYPE_DEFAULT);
73  if (IS_ERR(acl)) {
74  int err = PTR_ERR(acl);
75 
76  if (err == -ENODATA || err == -EOPNOTSUPP)
77  acl = NULL;
78  else {
79  nfserr = nfserrno(err);
80  goto fail;
81  }
82  }
83  resp->acl_default = acl;
84  }
85 
86  /* resp->acl_{access,default} are released in nfssvc_release_getacl. */
87  RETURN_STATUS(0);
88 
89 fail:
90  posix_acl_release(resp->acl_access);
91  posix_acl_release(resp->acl_default);
92  RETURN_STATUS(nfserr);
93 }
94 
95 /*
96  * Set the Access and/or Default ACL of a file.
97  */
98 static __be32 nfsacld_proc_setacl(struct svc_rqst * rqstp,
99  struct nfsd3_setaclargs *argp,
100  struct nfsd_attrstat *resp)
101 {
102  svc_fh *fh;
103  __be32 nfserr = 0;
104 
105  dprintk("nfsd: SETACL(2acl) %s\n", SVCFH_fmt(&argp->fh));
106 
107  fh = fh_copy(&resp->fh, &argp->fh);
108  nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_SATTR);
109 
110  if (!nfserr) {
111  nfserr = nfserrno( nfsd_set_posix_acl(
112  fh, ACL_TYPE_ACCESS, argp->acl_access) );
113  }
114  if (!nfserr) {
115  nfserr = nfserrno( nfsd_set_posix_acl(
116  fh, ACL_TYPE_DEFAULT, argp->acl_default) );
117  }
118 
119  /* argp->acl_{access,default} may have been allocated in
120  nfssvc_decode_setaclargs. */
121  posix_acl_release(argp->acl_access);
122  posix_acl_release(argp->acl_default);
123  return nfserr;
124 }
125 
126 /*
127  * Check file attributes
128  */
129 static __be32 nfsacld_proc_getattr(struct svc_rqst * rqstp,
130  struct nfsd_fhandle *argp, struct nfsd_attrstat *resp)
131 {
132  dprintk("nfsd: GETATTR %s\n", SVCFH_fmt(&argp->fh));
133 
134  fh_copy(&resp->fh, &argp->fh);
135  return fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP);
136 }
137 
138 /*
139  * Check file access
140  */
141 static __be32 nfsacld_proc_access(struct svc_rqst *rqstp, struct nfsd3_accessargs *argp,
142  struct nfsd3_accessres *resp)
143 {
144  __be32 nfserr;
145 
146  dprintk("nfsd: ACCESS(2acl) %s 0x%x\n",
147  SVCFH_fmt(&argp->fh),
148  argp->access);
149 
150  fh_copy(&resp->fh, &argp->fh);
151  resp->access = argp->access;
152  nfserr = nfsd_access(rqstp, &resp->fh, &resp->access, NULL);
153  return nfserr;
154 }
155 
156 /*
157  * XDR decode functions
158  */
159 static int nfsaclsvc_decode_getaclargs(struct svc_rqst *rqstp, __be32 *p,
160  struct nfsd3_getaclargs *argp)
161 {
162  if (!(p = nfs2svc_decode_fh(p, &argp->fh)))
163  return 0;
164  argp->mask = ntohl(*p); p++;
165 
166  return xdr_argsize_check(rqstp, p);
167 }
168 
169 
170 static int nfsaclsvc_decode_setaclargs(struct svc_rqst *rqstp, __be32 *p,
171  struct nfsd3_setaclargs *argp)
172 {
173  struct kvec *head = rqstp->rq_arg.head;
174  unsigned int base;
175  int n;
176 
177  if (!(p = nfs2svc_decode_fh(p, &argp->fh)))
178  return 0;
179  argp->mask = ntohl(*p++);
180  if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT) ||
181  !xdr_argsize_check(rqstp, p))
182  return 0;
183 
184  base = (char *)p - (char *)head->iov_base;
185  n = nfsacl_decode(&rqstp->rq_arg, base, NULL,
186  (argp->mask & NFS_ACL) ?
187  &argp->acl_access : NULL);
188  if (n > 0)
189  n = nfsacl_decode(&rqstp->rq_arg, base + n, NULL,
190  (argp->mask & NFS_DFACL) ?
191  &argp->acl_default : NULL);
192  return (n > 0);
193 }
194 
195 static int nfsaclsvc_decode_fhandleargs(struct svc_rqst *rqstp, __be32 *p,
196  struct nfsd_fhandle *argp)
197 {
198  if (!(p = nfs2svc_decode_fh(p, &argp->fh)))
199  return 0;
200  return xdr_argsize_check(rqstp, p);
201 }
202 
203 static int nfsaclsvc_decode_accessargs(struct svc_rqst *rqstp, __be32 *p,
204  struct nfsd3_accessargs *argp)
205 {
206  if (!(p = nfs2svc_decode_fh(p, &argp->fh)))
207  return 0;
208  argp->access = ntohl(*p++);
209 
210  return xdr_argsize_check(rqstp, p);
211 }
212 
213 /*
214  * XDR encode functions
215  */
216 
217 /*
218  * There must be an encoding function for void results so svc_process
219  * will work properly.
220  */
221 static int nfsaclsvc_encode_voidres(struct svc_rqst *rqstp, __be32 *p, void *dummy)
222 {
223  return xdr_ressize_check(rqstp, p);
224 }
225 
226 /* GETACL */
227 static 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,
269  if (n <= 0)
270  return 0;
271  return 1;
272 }
273 
274 static 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 */
282 static 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  */
293 static 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 
302 static 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 
309 static 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
321 struct 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 
340 static 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),
346 };
347 
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 };