2 * linux/fs/nfsd/nfs2acl.c
4 * Process version 2 NFSACL requests.
6 * Copyright (C) 2002-2003 Andreas Gruenbacher <agruen@suse.de>
9 #include <linux/sunrpc/svc.h>
10 #include <linux/nfs.h>
11 #include <linux/nfsd/nfsd.h>
12 #include <linux/nfsd/cache.h>
13 #include <linux/nfsd/xdr.h>
14 #include <linux/nfsd/xdr3.h>
15 #include <linux/posix_acl.h>
16 #include <linux/nfsacl.h>
19 #define NFSDDBG_FACILITY NFSDDBG_PROC
20 #define RETURN_STATUS(st) { resp->status = (st); return (st); }
26 nfsacld_proc_null(struct svc_rqst
*rqstp
, void *argp
, void *resp
)
32 * Get the Access and/or Default ACL of a file.
34 static __be32
nfsacld_proc_getacl(struct svc_rqst
* rqstp
,
35 struct nfsd3_getaclargs
*argp
, struct nfsd3_getaclres
*resp
)
38 struct posix_acl
*acl
;
41 dprintk("nfsd: GETACL(2acl) %s\n", SVCFH_fmt(&argp
->fh
));
43 fh
= fh_copy(&resp
->fh
, &argp
->fh
);
44 nfserr
= fh_verify(rqstp
, &resp
->fh
, 0, NFSD_MAY_NOP
);
46 RETURN_STATUS(nfserr
);
48 if (argp
->mask
& ~(NFS_ACL
|NFS_ACLCNT
|NFS_DFACL
|NFS_DFACLCNT
))
49 RETURN_STATUS(nfserr_inval
);
50 resp
->mask
= argp
->mask
;
52 if (resp
->mask
& (NFS_ACL
|NFS_ACLCNT
)) {
53 acl
= nfsd_get_posix_acl(fh
, ACL_TYPE_ACCESS
);
55 int err
= PTR_ERR(acl
);
57 if (err
== -ENODATA
|| err
== -EOPNOTSUPP
)
60 nfserr
= nfserrno(err
);
65 /* Solaris returns the inode's minimum ACL. */
67 struct inode
*inode
= fh
->fh_dentry
->d_inode
;
68 acl
= posix_acl_from_mode(inode
->i_mode
, GFP_KERNEL
);
70 resp
->acl_access
= acl
;
72 if (resp
->mask
& (NFS_DFACL
|NFS_DFACLCNT
)) {
73 /* Check how Solaris handles requests for the Default ACL
74 of a non-directory! */
76 acl
= nfsd_get_posix_acl(fh
, ACL_TYPE_DEFAULT
);
78 int err
= PTR_ERR(acl
);
80 if (err
== -ENODATA
|| err
== -EOPNOTSUPP
)
83 nfserr
= nfserrno(err
);
87 resp
->acl_default
= acl
;
90 /* resp->acl_{access,default} are released in nfssvc_release_getacl. */
94 posix_acl_release(resp
->acl_access
);
95 posix_acl_release(resp
->acl_default
);
96 RETURN_STATUS(nfserr
);
100 * Set the Access and/or Default ACL of a file.
102 static __be32
nfsacld_proc_setacl(struct svc_rqst
* rqstp
,
103 struct nfsd3_setaclargs
*argp
,
104 struct nfsd_attrstat
*resp
)
109 dprintk("nfsd: SETACL(2acl) %s\n", SVCFH_fmt(&argp
->fh
));
111 fh
= fh_copy(&resp
->fh
, &argp
->fh
);
112 nfserr
= fh_verify(rqstp
, &resp
->fh
, 0, NFSD_MAY_SATTR
);
115 nfserr
= nfserrno( nfsd_set_posix_acl(
116 fh
, ACL_TYPE_ACCESS
, argp
->acl_access
) );
119 nfserr
= nfserrno( nfsd_set_posix_acl(
120 fh
, ACL_TYPE_DEFAULT
, argp
->acl_default
) );
123 /* argp->acl_{access,default} may have been allocated in
124 nfssvc_decode_setaclargs. */
125 posix_acl_release(argp
->acl_access
);
126 posix_acl_release(argp
->acl_default
);
131 * Check file attributes
133 static __be32
nfsacld_proc_getattr(struct svc_rqst
* rqstp
,
134 struct nfsd_fhandle
*argp
, struct nfsd_attrstat
*resp
)
136 dprintk("nfsd: GETATTR %s\n", SVCFH_fmt(&argp
->fh
));
138 fh_copy(&resp
->fh
, &argp
->fh
);
139 return fh_verify(rqstp
, &resp
->fh
, 0, NFSD_MAY_NOP
);
145 static __be32
nfsacld_proc_access(struct svc_rqst
*rqstp
, struct nfsd3_accessargs
*argp
,
146 struct nfsd3_accessres
*resp
)
150 dprintk("nfsd: ACCESS(2acl) %s 0x%x\n",
151 SVCFH_fmt(&argp
->fh
),
154 fh_copy(&resp
->fh
, &argp
->fh
);
155 resp
->access
= argp
->access
;
156 nfserr
= nfsd_access(rqstp
, &resp
->fh
, &resp
->access
, NULL
);
161 * XDR decode functions
163 static int nfsaclsvc_decode_getaclargs(struct svc_rqst
*rqstp
, __be32
*p
,
164 struct nfsd3_getaclargs
*argp
)
166 if (!(p
= nfs2svc_decode_fh(p
, &argp
->fh
)))
168 argp
->mask
= ntohl(*p
); p
++;
170 return xdr_argsize_check(rqstp
, p
);
174 static int nfsaclsvc_decode_setaclargs(struct svc_rqst
*rqstp
, __be32
*p
,
175 struct nfsd3_setaclargs
*argp
)
177 struct kvec
*head
= rqstp
->rq_arg
.head
;
181 if (!(p
= nfs2svc_decode_fh(p
, &argp
->fh
)))
183 argp
->mask
= ntohl(*p
++);
184 if (argp
->mask
& ~(NFS_ACL
|NFS_ACLCNT
|NFS_DFACL
|NFS_DFACLCNT
) ||
185 !xdr_argsize_check(rqstp
, p
))
188 base
= (char *)p
- (char *)head
->iov_base
;
189 n
= nfsacl_decode(&rqstp
->rq_arg
, base
, NULL
,
190 (argp
->mask
& NFS_ACL
) ?
191 &argp
->acl_access
: NULL
);
193 n
= nfsacl_decode(&rqstp
->rq_arg
, base
+ n
, NULL
,
194 (argp
->mask
& NFS_DFACL
) ?
195 &argp
->acl_default
: NULL
);
199 static int nfsaclsvc_decode_fhandleargs(struct svc_rqst
*rqstp
, __be32
*p
,
200 struct nfsd_fhandle
*argp
)
202 if (!(p
= nfs2svc_decode_fh(p
, &argp
->fh
)))
204 return xdr_argsize_check(rqstp
, p
);
207 static int nfsaclsvc_decode_accessargs(struct svc_rqst
*rqstp
, __be32
*p
,
208 struct nfsd3_accessargs
*argp
)
210 if (!(p
= nfs2svc_decode_fh(p
, &argp
->fh
)))
212 argp
->access
= ntohl(*p
++);
214 return xdr_argsize_check(rqstp
, p
);
218 * XDR encode functions
222 * There must be an encoding function for void results so svc_process
223 * will work properly.
226 nfsaclsvc_encode_voidres(struct svc_rqst
*rqstp
, __be32
*p
, void *dummy
)
228 return xdr_ressize_check(rqstp
, p
);
232 static int nfsaclsvc_encode_getaclres(struct svc_rqst
*rqstp
, __be32
*p
,
233 struct nfsd3_getaclres
*resp
)
235 struct dentry
*dentry
= resp
->fh
.fh_dentry
;
237 struct kvec
*head
= rqstp
->rq_res
.head
;
243 * Since this is version 2, the check for nfserr in
244 * nfsd_dispatch actually ensures the following cannot happen.
245 * However, it seems fragile to depend on that.
247 if (dentry
== NULL
|| dentry
->d_inode
== NULL
)
249 inode
= dentry
->d_inode
;
251 p
= nfs2svc_encode_fattr(rqstp
, p
, &resp
->fh
);
252 *p
++ = htonl(resp
->mask
);
253 if (!xdr_ressize_check(rqstp
, p
))
255 base
= (char *)p
- (char *)head
->iov_base
;
257 rqstp
->rq_res
.page_len
= w
= nfsacl_size(
258 (resp
->mask
& NFS_ACL
) ? resp
->acl_access
: NULL
,
259 (resp
->mask
& NFS_DFACL
) ? resp
->acl_default
: NULL
);
261 if (!rqstp
->rq_respages
[rqstp
->rq_resused
++])
266 n
= nfsacl_encode(&rqstp
->rq_res
, base
, inode
,
268 resp
->mask
& NFS_ACL
, 0);
270 n
= nfsacl_encode(&rqstp
->rq_res
, base
+ n
, inode
,
272 resp
->mask
& NFS_DFACL
,
279 static int nfsaclsvc_encode_attrstatres(struct svc_rqst
*rqstp
, __be32
*p
,
280 struct nfsd_attrstat
*resp
)
282 p
= nfs2svc_encode_fattr(rqstp
, p
, &resp
->fh
);
283 return xdr_ressize_check(rqstp
, p
);
287 static int nfsaclsvc_encode_accessres(struct svc_rqst
*rqstp
, __be32
*p
,
288 struct nfsd3_accessres
*resp
)
290 p
= nfs2svc_encode_fattr(rqstp
, p
, &resp
->fh
);
291 *p
++ = htonl(resp
->access
);
292 return xdr_ressize_check(rqstp
, p
);
296 * XDR release functions
298 static int nfsaclsvc_release_getacl(struct svc_rqst
*rqstp
, __be32
*p
,
299 struct nfsd3_getaclres
*resp
)
302 posix_acl_release(resp
->acl_access
);
303 posix_acl_release(resp
->acl_default
);
307 static int nfsaclsvc_release_attrstat(struct svc_rqst
*rqstp
, __be32
*p
,
308 struct nfsd_attrstat
*resp
)
314 static int nfsaclsvc_release_access(struct svc_rqst
*rqstp
, __be32
*p
,
315 struct nfsd3_accessres
*resp
)
321 #define nfsaclsvc_decode_voidargs NULL
322 #define nfsaclsvc_release_void NULL
323 #define nfsd3_fhandleargs nfsd_fhandle
324 #define nfsd3_attrstatres nfsd_attrstat
325 #define nfsd3_voidres nfsd3_voidargs
326 struct nfsd3_voidargs
{ int dummy
; };
328 #define PROC(name, argt, rest, relt, cache, respsize) \
329 { (svc_procfunc) nfsacld_proc_##name, \
330 (kxdrproc_t) nfsaclsvc_decode_##argt##args, \
331 (kxdrproc_t) nfsaclsvc_encode_##rest##res, \
332 (kxdrproc_t) nfsaclsvc_release_##relt, \
333 sizeof(struct nfsd3_##argt##args), \
334 sizeof(struct nfsd3_##rest##res), \
340 #define ST 1 /* status*/
341 #define AT 21 /* attributes */
342 #define pAT (1+AT) /* post attributes - conditional */
343 #define ACL (1+NFS_ACL_MAX_ENTRIES*3) /* Access Control List */
345 static struct svc_procedure nfsd_acl_procedures2
[] = {
346 PROC(null
, void, void, void, RC_NOCACHE
, ST
),
347 PROC(getacl
, getacl
, getacl
, getacl
, RC_NOCACHE
, ST
+1+2*(1+ACL
)),
348 PROC(setacl
, setacl
, attrstat
, attrstat
, RC_NOCACHE
, ST
+AT
),
349 PROC(getattr
, fhandle
, attrstat
, attrstat
, RC_NOCACHE
, ST
+AT
),
350 PROC(access
, access
, access
, access
, RC_NOCACHE
, ST
+AT
+1),
353 struct svc_version nfsd_acl_version2
= {
356 .vs_proc
= nfsd_acl_procedures2
,
357 .vs_dispatch
= nfsd_dispatch
,
358 .vs_xdrsize
= NFS3_SVC_XDRSIZE
,