NFSD: Update the NFSv2 ACL GETATTR argument decoder to use struct xdr_stream
[linux-block.git] / fs / nfsd / nfs2acl.c
CommitLineData
b2441318 1// SPDX-License-Identifier: GPL-2.0
a257cdd0 2/*
a257cdd0
AG
3 * Process version 2 NFSACL requests.
4 *
5 * Copyright (C) 2002-2003 Andreas Gruenbacher <agruen@suse.de>
6 */
7
9a74af21
BH
8#include "nfsd.h"
9/* FIXME: nfsacl.h is a broken header */
a257cdd0 10#include <linux/nfsacl.h>
5a0e3ad6 11#include <linux/gfp.h>
9a74af21
BH
12#include "cache.h"
13#include "xdr3.h"
0a3adade 14#include "vfs.h"
a257cdd0
AG
15
16#define NFSDDBG_FACILITY NFSDDBG_PROC
a257cdd0
AG
17
18/*
19 * NULL call.
20 */
7111c66e 21static __be32
a6beb732 22nfsacld_proc_null(struct svc_rqst *rqstp)
a257cdd0 23{
cc028a10 24 return rpc_success;
a257cdd0
AG
25}
26
27/*
28 * Get the Access and/or Default ACL of a file.
29 */
a6beb732 30static __be32 nfsacld_proc_getacl(struct svc_rqst *rqstp)
a257cdd0 31{
a6beb732
CH
32 struct nfsd3_getaclargs *argp = rqstp->rq_argp;
33 struct nfsd3_getaclres *resp = rqstp->rq_resp;
a257cdd0 34 struct posix_acl *acl;
4ac7249e
CH
35 struct inode *inode;
36 svc_fh *fh;
a257cdd0
AG
37
38 dprintk("nfsd: GETACL(2acl) %s\n", SVCFH_fmt(&argp->fh));
39
40 fh = fh_copy(&resp->fh, &argp->fh);
f0af2210
CL
41 resp->status = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP);
42 if (resp->status != nfs_ok)
43 goto out;
a257cdd0 44
2b0143b5 45 inode = d_inode(fh->fh_dentry);
4ac7249e 46
f0af2210
CL
47 if (argp->mask & ~NFS_ACL_MASK) {
48 resp->status = nfserr_inval;
49 goto out;
50 }
a257cdd0
AG
51 resp->mask = argp->mask;
52
f0af2210
CL
53 resp->status = fh_getattr(fh, &resp->stat);
54 if (resp->status != nfs_ok)
55 goto out;
4f4a4fad 56
a257cdd0 57 if (resp->mask & (NFS_ACL|NFS_ACLCNT)) {
4ac7249e 58 acl = get_acl(inode, ACL_TYPE_ACCESS);
a257cdd0
AG
59 if (acl == NULL) {
60 /* Solaris returns the inode's minimum ACL. */
a257cdd0
AG
61 acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
62 }
35e634b8 63 if (IS_ERR(acl)) {
f0af2210 64 resp->status = nfserrno(PTR_ERR(acl));
35e634b8
KM
65 goto fail;
66 }
a257cdd0
AG
67 resp->acl_access = acl;
68 }
69 if (resp->mask & (NFS_DFACL|NFS_DFACLCNT)) {
70 /* Check how Solaris handles requests for the Default ACL
71 of a non-directory! */
4ac7249e 72 acl = get_acl(inode, ACL_TYPE_DEFAULT);
a257cdd0 73 if (IS_ERR(acl)) {
f0af2210 74 resp->status = nfserrno(PTR_ERR(acl));
4ac7249e 75 goto fail;
a257cdd0
AG
76 }
77 resp->acl_default = acl;
78 }
79
80 /* resp->acl_{access,default} are released in nfssvc_release_getacl. */
f0af2210 81out:
cc028a10 82 return rpc_success;
a257cdd0
AG
83
84fail:
85 posix_acl_release(resp->acl_access);
86 posix_acl_release(resp->acl_default);
f0af2210 87 goto out;
a257cdd0
AG
88}
89
90/*
91 * Set the Access and/or Default ACL of a file.
92 */
a6beb732 93static __be32 nfsacld_proc_setacl(struct svc_rqst *rqstp)
a257cdd0 94{
a6beb732
CH
95 struct nfsd3_setaclargs *argp = rqstp->rq_argp;
96 struct nfsd_attrstat *resp = rqstp->rq_resp;
4ac7249e 97 struct inode *inode;
a257cdd0 98 svc_fh *fh;
4ac7249e 99 int error;
a257cdd0
AG
100
101 dprintk("nfsd: SETACL(2acl) %s\n", SVCFH_fmt(&argp->fh));
102
103 fh = fh_copy(&resp->fh, &argp->fh);
f0af2210
CL
104 resp->status = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_SATTR);
105 if (resp->status != nfs_ok)
4ac7249e 106 goto out;
a257cdd0 107
2b0143b5 108 inode = d_inode(fh->fh_dentry);
a257cdd0 109
4ac7249e
CH
110 error = fh_want_write(fh);
111 if (error)
112 goto out_errno;
113
99965378
BH
114 fh_lock(fh);
115
116 error = set_posix_acl(inode, ACL_TYPE_ACCESS, argp->acl_access);
4ac7249e 117 if (error)
99965378
BH
118 goto out_drop_lock;
119 error = set_posix_acl(inode, ACL_TYPE_DEFAULT, argp->acl_default);
4ac7249e 120 if (error)
99965378
BH
121 goto out_drop_lock;
122
123 fh_unlock(fh);
4ac7249e
CH
124
125 fh_drop_write(fh);
126
f0af2210 127 resp->status = fh_getattr(fh, &resp->stat);
4ac7249e
CH
128
129out:
a257cdd0
AG
130 /* argp->acl_{access,default} may have been allocated in
131 nfssvc_decode_setaclargs. */
132 posix_acl_release(argp->acl_access);
133 posix_acl_release(argp->acl_default);
cc028a10 134 return rpc_success;
f0af2210 135
99965378
BH
136out_drop_lock:
137 fh_unlock(fh);
4ac7249e
CH
138 fh_drop_write(fh);
139out_errno:
f0af2210 140 resp->status = nfserrno(error);
4ac7249e 141 goto out;
a257cdd0
AG
142}
143
144/*
145 * Check file attributes
146 */
a6beb732 147static __be32 nfsacld_proc_getattr(struct svc_rqst *rqstp)
a257cdd0 148{
a6beb732
CH
149 struct nfsd_fhandle *argp = rqstp->rq_argp;
150 struct nfsd_attrstat *resp = rqstp->rq_resp;
f0af2210 151
a257cdd0
AG
152 dprintk("nfsd: GETATTR %s\n", SVCFH_fmt(&argp->fh));
153
154 fh_copy(&resp->fh, &argp->fh);
f0af2210
CL
155 resp->status = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP);
156 if (resp->status != nfs_ok)
157 goto out;
158 resp->status = fh_getattr(&resp->fh, &resp->stat);
159out:
cc028a10 160 return rpc_success;
a257cdd0
AG
161}
162
163/*
164 * Check file access
165 */
a6beb732 166static __be32 nfsacld_proc_access(struct svc_rqst *rqstp)
a257cdd0 167{
a6beb732
CH
168 struct nfsd3_accessargs *argp = rqstp->rq_argp;
169 struct nfsd3_accessres *resp = rqstp->rq_resp;
a257cdd0
AG
170
171 dprintk("nfsd: ACCESS(2acl) %s 0x%x\n",
172 SVCFH_fmt(&argp->fh),
173 argp->access);
174
175 fh_copy(&resp->fh, &argp->fh);
176 resp->access = argp->access;
f0af2210
CL
177 resp->status = nfsd_access(rqstp, &resp->fh, &resp->access, NULL);
178 if (resp->status != nfs_ok)
179 goto out;
180 resp->status = fh_getattr(&resp->fh, &resp->stat);
181out:
cc028a10 182 return rpc_success;
a257cdd0
AG
183}
184
185/*
186 * XDR decode functions
187 */
dcc46991 188
026fec7e 189static int nfsaclsvc_decode_getaclargs(struct svc_rqst *rqstp, __be32 *p)
a257cdd0 190{
635a45d3 191 struct xdr_stream *xdr = &rqstp->rq_arg_stream;
026fec7e
CH
192 struct nfsd3_getaclargs *argp = rqstp->rq_argp;
193
635a45d3
CL
194 if (!svcxdr_decode_fhandle(xdr, &argp->fh))
195 return 0;
196 if (xdr_stream_decode_u32(xdr, &argp->mask) < 0)
a257cdd0 197 return 0;
a257cdd0 198
635a45d3 199 return 1;
a257cdd0
AG
200}
201
026fec7e 202static int nfsaclsvc_decode_setaclargs(struct svc_rqst *rqstp, __be32 *p)
a257cdd0 203{
427eab3b 204 struct xdr_stream *xdr = &rqstp->rq_arg_stream;
026fec7e 205 struct nfsd3_setaclargs *argp = rqstp->rq_argp;
a257cdd0 206
427eab3b 207 if (!svcxdr_decode_fhandle(xdr, &argp->fh))
a257cdd0 208 return 0;
427eab3b
CL
209 if (xdr_stream_decode_u32(xdr, &argp->mask) < 0)
210 return 0;
211 if (argp->mask & ~NFS_ACL_MASK)
212 return 0;
213 if (!nfs_stream_decode_acl(xdr, NULL, (argp->mask & NFS_ACL) ?
214 &argp->acl_access : NULL))
215 return 0;
216 if (!nfs_stream_decode_acl(xdr, NULL, (argp->mask & NFS_DFACL) ?
217 &argp->acl_default : NULL))
a257cdd0
AG
218 return 0;
219
427eab3b 220 return 1;
a257cdd0
AG
221}
222
026fec7e 223static int nfsaclsvc_decode_accessargs(struct svc_rqst *rqstp, __be32 *p)
a257cdd0 224{
026fec7e
CH
225 struct nfsd3_accessargs *argp = rqstp->rq_argp;
226
d40aa337
BT
227 p = nfs2svc_decode_fh(p, &argp->fh);
228 if (!p)
a257cdd0
AG
229 return 0;
230 argp->access = ntohl(*p++);
231
232 return xdr_argsize_check(rqstp, p);
233}
234
235/*
236 * XDR encode functions
237 */
238
239/* GETACL */
63f8de37 240static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p)
a257cdd0 241{
63f8de37 242 struct nfsd3_getaclres *resp = rqstp->rq_resp;
a257cdd0 243 struct dentry *dentry = resp->fh.fh_dentry;
aefa89d1 244 struct inode *inode;
a257cdd0
AG
245 struct kvec *head = rqstp->rq_res.head;
246 unsigned int base;
247 int n;
cb65a5ba 248 int w;
a257cdd0 249
cc028a10 250 *p++ = resp->status;
f0af2210
CL
251 if (resp->status != nfs_ok)
252 return xdr_ressize_check(rqstp, p);
253
aefa89d1
P
254 /*
255 * Since this is version 2, the check for nfserr in
256 * nfsd_dispatch actually ensures the following cannot happen.
257 * However, it seems fragile to depend on that.
258 */
2b0143b5 259 if (dentry == NULL || d_really_is_negative(dentry))
a257cdd0 260 return 0;
2b0143b5 261 inode = d_inode(dentry);
a257cdd0 262
4f4a4fad 263 p = nfs2svc_encode_fattr(rqstp, p, &resp->fh, &resp->stat);
a257cdd0
AG
264 *p++ = htonl(resp->mask);
265 if (!xdr_ressize_check(rqstp, p))
266 return 0;
267 base = (char *)p - (char *)head->iov_base;
268
cb65a5ba
JJ
269 rqstp->rq_res.page_len = w = nfsacl_size(
270 (resp->mask & NFS_ACL) ? resp->acl_access : NULL,
271 (resp->mask & NFS_DFACL) ? resp->acl_default : NULL);
a257cdd0 272 while (w > 0) {
afc59400 273 if (!*(rqstp->rq_next_page++))
a257cdd0
AG
274 return 0;
275 w -= PAGE_SIZE;
276 }
277
278 n = nfsacl_encode(&rqstp->rq_res, base, inode,
279 resp->acl_access,
280 resp->mask & NFS_ACL, 0);
281 if (n > 0)
282 n = nfsacl_encode(&rqstp->rq_res, base + n, inode,
283 resp->acl_default,
284 resp->mask & NFS_DFACL,
285 NFS_ACL_DEFAULT);
7b8f4586 286 return (n > 0);
a257cdd0
AG
287}
288
63f8de37 289static int nfsaclsvc_encode_attrstatres(struct svc_rqst *rqstp, __be32 *p)
a257cdd0 290{
63f8de37
CH
291 struct nfsd_attrstat *resp = rqstp->rq_resp;
292
cc028a10 293 *p++ = resp->status;
f0af2210 294 if (resp->status != nfs_ok)
cc028a10 295 goto out;
f0af2210 296
4f4a4fad 297 p = nfs2svc_encode_fattr(rqstp, p, &resp->fh, &resp->stat);
cc028a10 298out:
a257cdd0
AG
299 return xdr_ressize_check(rqstp, p);
300}
301
302/* ACCESS */
63f8de37 303static int nfsaclsvc_encode_accessres(struct svc_rqst *rqstp, __be32 *p)
a257cdd0 304{
63f8de37
CH
305 struct nfsd3_accessres *resp = rqstp->rq_resp;
306
cc028a10 307 *p++ = resp->status;
f0af2210 308 if (resp->status != nfs_ok)
cc028a10 309 goto out;
f0af2210 310
4f4a4fad 311 p = nfs2svc_encode_fattr(rqstp, p, &resp->fh, &resp->stat);
a257cdd0 312 *p++ = htonl(resp->access);
cc028a10 313out:
a257cdd0
AG
314 return xdr_ressize_check(rqstp, p);
315}
316
317/*
318 * XDR release functions
319 */
8537488b 320static void nfsaclsvc_release_getacl(struct svc_rqst *rqstp)
a257cdd0 321{
8537488b
CH
322 struct nfsd3_getaclres *resp = rqstp->rq_resp;
323
a257cdd0
AG
324 fh_put(&resp->fh);
325 posix_acl_release(resp->acl_access);
326 posix_acl_release(resp->acl_default);
a257cdd0
AG
327}
328
8537488b 329static void nfsaclsvc_release_attrstat(struct svc_rqst *rqstp)
a257cdd0 330{
8537488b
CH
331 struct nfsd_attrstat *resp = rqstp->rq_resp;
332
a257cdd0 333 fh_put(&resp->fh);
a257cdd0
AG
334}
335
8537488b 336static void nfsaclsvc_release_access(struct svc_rqst *rqstp)
c9ce2283 337{
8537488b
CH
338 struct nfsd3_accessres *resp = rqstp->rq_resp;
339
340 fh_put(&resp->fh);
c9ce2283
GB
341}
342
a257cdd0
AG
343struct nfsd3_voidargs { int dummy; };
344
a257cdd0
AG
345#define ST 1 /* status*/
346#define AT 21 /* attributes */
347#define pAT (1+AT) /* post attributes - conditional */
348#define ACL (1+NFS_ACL_MAX_ENTRIES*3) /* Access Control List */
349
ba1df797
CL
350static const struct svc_procedure nfsd_acl_procedures2[5] = {
351 [ACLPROC2_NULL] = {
352 .pc_func = nfsacld_proc_null,
788f7183
CL
353 .pc_decode = nfssvc_decode_voidarg,
354 .pc_encode = nfssvc_encode_voidres,
355 .pc_argsize = sizeof(struct nfsd_voidargs),
356 .pc_ressize = sizeof(struct nfsd_voidres),
ba1df797
CL
357 .pc_cachetype = RC_NOCACHE,
358 .pc_xdrressize = ST,
2289e87b 359 .pc_name = "NULL",
ba1df797
CL
360 },
361 [ACLPROC2_GETACL] = {
362 .pc_func = nfsacld_proc_getacl,
363 .pc_decode = nfsaclsvc_decode_getaclargs,
364 .pc_encode = nfsaclsvc_encode_getaclres,
365 .pc_release = nfsaclsvc_release_getacl,
366 .pc_argsize = sizeof(struct nfsd3_getaclargs),
367 .pc_ressize = sizeof(struct nfsd3_getaclres),
368 .pc_cachetype = RC_NOCACHE,
369 .pc_xdrressize = ST+1+2*(1+ACL),
2289e87b 370 .pc_name = "GETACL",
ba1df797
CL
371 },
372 [ACLPROC2_SETACL] = {
373 .pc_func = nfsacld_proc_setacl,
374 .pc_decode = nfsaclsvc_decode_setaclargs,
375 .pc_encode = nfsaclsvc_encode_attrstatres,
376 .pc_release = nfsaclsvc_release_attrstat,
377 .pc_argsize = sizeof(struct nfsd3_setaclargs),
378 .pc_ressize = sizeof(struct nfsd_attrstat),
379 .pc_cachetype = RC_NOCACHE,
380 .pc_xdrressize = ST+AT,
2289e87b 381 .pc_name = "SETACL",
ba1df797
CL
382 },
383 [ACLPROC2_GETATTR] = {
384 .pc_func = nfsacld_proc_getattr,
571d31f3 385 .pc_decode = nfssvc_decode_fhandleargs,
ba1df797
CL
386 .pc_encode = nfsaclsvc_encode_attrstatres,
387 .pc_release = nfsaclsvc_release_attrstat,
388 .pc_argsize = sizeof(struct nfsd_fhandle),
389 .pc_ressize = sizeof(struct nfsd_attrstat),
390 .pc_cachetype = RC_NOCACHE,
391 .pc_xdrressize = ST+AT,
2289e87b 392 .pc_name = "GETATTR",
ba1df797
CL
393 },
394 [ACLPROC2_ACCESS] = {
395 .pc_func = nfsacld_proc_access,
396 .pc_decode = nfsaclsvc_decode_accessargs,
397 .pc_encode = nfsaclsvc_encode_accessres,
398 .pc_release = nfsaclsvc_release_access,
399 .pc_argsize = sizeof(struct nfsd3_accessargs),
400 .pc_ressize = sizeof(struct nfsd3_accessres),
401 .pc_cachetype = RC_NOCACHE,
402 .pc_xdrressize = ST+AT+1,
2289e87b 403 .pc_name = "SETATTR",
ba1df797 404 },
a257cdd0
AG
405};
406
7fd38af9 407static unsigned int nfsd_acl_count2[ARRAY_SIZE(nfsd_acl_procedures2)];
e9679189
CH
408const struct svc_version nfsd_acl_version2 = {
409 .vs_vers = 2,
410 .vs_nproc = 5,
411 .vs_proc = nfsd_acl_procedures2,
412 .vs_count = nfsd_acl_count2,
413 .vs_dispatch = nfsd_dispatch,
414 .vs_xdrsize = NFS3_SVC_XDRSIZE,
a257cdd0 415};