Root/
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 | 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 | int |
222 | nfsaclsvc_encode_voidres(struct svc_rqst *rqstp, __be32 *p, void *dummy) |
223 | { |
224 | return xdr_ressize_check(rqstp, p); |
225 | } |
226 | |
227 | /* GETACL */ |
228 | static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p, |
229 | struct nfsd3_getaclres *resp) |
230 | { |
231 | struct dentry *dentry = resp->fh.fh_dentry; |
232 | struct inode *inode; |
233 | struct kvec *head = rqstp->rq_res.head; |
234 | unsigned int base; |
235 | int n; |
236 | int w; |
237 | |
238 | /* |
239 | * Since this is version 2, the check for nfserr in |
240 | * nfsd_dispatch actually ensures the following cannot happen. |
241 | * However, it seems fragile to depend on that. |
242 | */ |
243 | if (dentry == NULL || dentry->d_inode == NULL) |
244 | return 0; |
245 | inode = dentry->d_inode; |
246 | |
247 | p = nfs2svc_encode_fattr(rqstp, p, &resp->fh); |
248 | *p++ = htonl(resp->mask); |
249 | if (!xdr_ressize_check(rqstp, p)) |
250 | return 0; |
251 | base = (char *)p - (char *)head->iov_base; |
252 | |
253 | rqstp->rq_res.page_len = w = nfsacl_size( |
254 | (resp->mask & NFS_ACL) ? resp->acl_access : NULL, |
255 | (resp->mask & NFS_DFACL) ? resp->acl_default : NULL); |
256 | while (w > 0) { |
257 | if (!rqstp->rq_respages[rqstp->rq_resused++]) |
258 | return 0; |
259 | w -= PAGE_SIZE; |
260 | } |
261 | |
262 | n = nfsacl_encode(&rqstp->rq_res, base, inode, |
263 | resp->acl_access, |
264 | resp->mask & NFS_ACL, 0); |
265 | if (n > 0) |
266 | n = nfsacl_encode(&rqstp->rq_res, base + n, inode, |
267 | resp->acl_default, |
268 | resp->mask & NFS_DFACL, |
269 | NFS_ACL_DEFAULT); |
270 | if (n <= 0) |
271 | return 0; |
272 | return 1; |
273 | } |
274 | |
275 | static int nfsaclsvc_encode_attrstatres(struct svc_rqst *rqstp, __be32 *p, |
276 | struct nfsd_attrstat *resp) |
277 | { |
278 | p = nfs2svc_encode_fattr(rqstp, p, &resp->fh); |
279 | return xdr_ressize_check(rqstp, p); |
280 | } |
281 | |
282 | /* ACCESS */ |
283 | static int nfsaclsvc_encode_accessres(struct svc_rqst *rqstp, __be32 *p, |
284 | struct nfsd3_accessres *resp) |
285 | { |
286 | p = nfs2svc_encode_fattr(rqstp, p, &resp->fh); |
287 | *p++ = htonl(resp->access); |
288 | return xdr_ressize_check(rqstp, p); |
289 | } |
290 | |
291 | /* |
292 | * XDR release functions |
293 | */ |
294 | static int nfsaclsvc_release_getacl(struct svc_rqst *rqstp, __be32 *p, |
295 | struct nfsd3_getaclres *resp) |
296 | { |
297 | fh_put(&resp->fh); |
298 | posix_acl_release(resp->acl_access); |
299 | posix_acl_release(resp->acl_default); |
300 | return 1; |
301 | } |
302 | |
303 | static int nfsaclsvc_release_attrstat(struct svc_rqst *rqstp, __be32 *p, |
304 | struct nfsd_attrstat *resp) |
305 | { |
306 | fh_put(&resp->fh); |
307 | return 1; |
308 | } |
309 | |
310 | static int nfsaclsvc_release_access(struct svc_rqst *rqstp, __be32 *p, |
311 | struct nfsd3_accessres *resp) |
312 | { |
313 | fh_put(&resp->fh); |
314 | return 1; |
315 | } |
316 | |
317 | #define nfsaclsvc_decode_voidargs NULL |
318 | #define nfsaclsvc_release_void NULL |
319 | #define nfsd3_fhandleargs nfsd_fhandle |
320 | #define nfsd3_attrstatres nfsd_attrstat |
321 | #define nfsd3_voidres nfsd3_voidargs |
322 | struct nfsd3_voidargs { int dummy; }; |
323 | |
324 | #define PROC(name, argt, rest, relt, cache, respsize) \ |
325 | { (svc_procfunc) nfsacld_proc_##name, \ |
326 | (kxdrproc_t) nfsaclsvc_decode_##argt##args, \ |
327 | (kxdrproc_t) nfsaclsvc_encode_##rest##res, \ |
328 | (kxdrproc_t) nfsaclsvc_release_##relt, \ |
329 | sizeof(struct nfsd3_##argt##args), \ |
330 | sizeof(struct nfsd3_##rest##res), \ |
331 | 0, \ |
332 | cache, \ |
333 | respsize, \ |
334 | } |
335 | |
336 | #define ST 1 /* status*/ |
337 | #define AT 21 /* attributes */ |
338 | #define pAT (1+AT) /* post attributes - conditional */ |
339 | #define ACL (1+NFS_ACL_MAX_ENTRIES*3) /* Access Control List */ |
340 | |
341 | static struct svc_procedure nfsd_acl_procedures2[] = { |
342 | PROC(null, void, void, void, RC_NOCACHE, ST), |
343 | PROC(getacl, getacl, getacl, getacl, RC_NOCACHE, ST+1+2*(1+ACL)), |
344 | PROC(setacl, setacl, attrstat, attrstat, RC_NOCACHE, ST+AT), |
345 | PROC(getattr, fhandle, attrstat, attrstat, RC_NOCACHE, ST+AT), |
346 | PROC(access, access, access, access, RC_NOCACHE, ST+AT+1), |
347 | }; |
348 | |
349 | struct svc_version nfsd_acl_version2 = { |
350 | .vs_vers = 2, |
351 | .vs_nproc = 5, |
352 | .vs_proc = nfsd_acl_procedures2, |
353 | .vs_dispatch = nfsd_dispatch, |
354 | .vs_xdrsize = NFS3_SVC_XDRSIZE, |
355 | .vs_hidden = 0, |
356 | }; |
357 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9