1/* 2 * Process version 3 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 RETURN_STATUS(st) { resp->status = (st); return (st); } 15 16/* 17 * NULL call. 18 */ 19static __be32 20nfsd3_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) 21{ 22 return nfs_ok; 23} 24 25/* 26 * Get the Access and/or Default ACL of a file. 27 */ 28static __be32 nfsd3_proc_getacl(struct svc_rqst * rqstp, 29 struct nfsd3_getaclargs *argp, struct nfsd3_getaclres *resp) 30{ 31 svc_fh *fh; 32 struct posix_acl *acl; 33 __be32 nfserr = 0; 34 35 fh = fh_copy(&resp->fh, &argp->fh); 36 nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP); 37 if (nfserr) 38 RETURN_STATUS(nfserr); 39 40 if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT)) 41 RETURN_STATUS(nfserr_inval); 42 resp->mask = argp->mask; 43 44 if (resp->mask & (NFS_ACL|NFS_ACLCNT)) { 45 acl = nfsd_get_posix_acl(fh, ACL_TYPE_ACCESS); 46 if (IS_ERR(acl)) { 47 int err = PTR_ERR(acl); 48 49 if (err == -ENODATA || err == -EOPNOTSUPP) 50 acl = NULL; 51 else { 52 nfserr = nfserrno(err); 53 goto fail; 54 } 55 } 56 if (acl == NULL) { 57 /* Solaris returns the inode's minimum ACL. */ 58 59 struct inode *inode = fh->fh_dentry->d_inode; 60 acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL); 61 } 62 resp->acl_access = acl; 63 } 64 if (resp->mask & (NFS_DFACL|NFS_DFACLCNT)) { 65 /* Check how Solaris handles requests for the Default ACL 66 of a non-directory! */ 67 68 acl = nfsd_get_posix_acl(fh, ACL_TYPE_DEFAULT); 69 if (IS_ERR(acl)) { 70 int err = PTR_ERR(acl); 71 72 if (err == -ENODATA || err == -EOPNOTSUPP) 73 acl = NULL; 74 else { 75 nfserr = nfserrno(err); 76 goto fail; 77 } 78 } 79 resp->acl_default = acl; 80 } 81 82 /* resp->acl_{access,default} are released in nfs3svc_release_getacl. */ 83 RETURN_STATUS(0); 84 85fail: 86 posix_acl_release(resp->acl_access); 87 posix_acl_release(resp->acl_default); 88 RETURN_STATUS(nfserr); 89} 90 91/* 92 * Set the Access and/or Default ACL of a file. 93 */ 94static __be32 nfsd3_proc_setacl(struct svc_rqst * rqstp, 95 struct nfsd3_setaclargs *argp, 96 struct nfsd3_attrstat *resp) 97{ 98 svc_fh *fh; 99 __be32 nfserr = 0; 100 101 fh = fh_copy(&resp->fh, &argp->fh); 102 nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_SATTR); 103 104 if (!nfserr) { 105 nfserr = nfserrno( nfsd_set_posix_acl( 106 fh, ACL_TYPE_ACCESS, argp->acl_access) ); 107 } 108 if (!nfserr) { 109 nfserr = nfserrno( nfsd_set_posix_acl( 110 fh, ACL_TYPE_DEFAULT, argp->acl_default) ); 111 } 112 113 /* argp->acl_{access,default} may have been allocated in 114 nfs3svc_decode_setaclargs. */ 115 posix_acl_release(argp->acl_access); 116 posix_acl_release(argp->acl_default); 117 RETURN_STATUS(nfserr); 118} 119 120/* 121 * XDR decode functions 122 */ 123static int nfs3svc_decode_getaclargs(struct svc_rqst *rqstp, __be32 *p, 124 struct nfsd3_getaclargs *args) 125{ 126 if (!(p = nfs3svc_decode_fh(p, &args->fh))) 127 return 0; 128 args->mask = ntohl(*p); p++; 129 130 return xdr_argsize_check(rqstp, p); 131} 132 133 134static int nfs3svc_decode_setaclargs(struct svc_rqst *rqstp, __be32 *p, 135 struct nfsd3_setaclargs *args) 136{ 137 struct kvec *head = rqstp->rq_arg.head; 138 unsigned int base; 139 int n; 140 141 if (!(p = nfs3svc_decode_fh(p, &args->fh))) 142 return 0; 143 args->mask = ntohl(*p++); 144 if (args->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT) || 145 !xdr_argsize_check(rqstp, p)) 146 return 0; 147 148 base = (char *)p - (char *)head->iov_base; 149 n = nfsacl_decode(&rqstp->rq_arg, base, NULL, 150 (args->mask & NFS_ACL) ? 151 &args->acl_access : NULL); 152 if (n > 0) 153 n = nfsacl_decode(&rqstp->rq_arg, base + n, NULL, 154 (args->mask & NFS_DFACL) ? 155 &args->acl_default : NULL); 156 return (n > 0); 157} 158 159/* 160 * XDR encode functions 161 */ 162 163/* GETACL */ 164static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p, 165 struct nfsd3_getaclres *resp) 166{ 167 struct dentry *dentry = resp->fh.fh_dentry; 168 169 p = nfs3svc_encode_post_op_attr(rqstp, p, &resp->fh); 170 if (resp->status == 0 && dentry && dentry->d_inode) { 171 struct inode *inode = dentry->d_inode; 172 struct kvec *head = rqstp->rq_res.head; 173 unsigned int base; 174 int n; 175 int w; 176 177 *p++ = htonl(resp->mask); 178 if (!xdr_ressize_check(rqstp, p)) 179 return 0; 180 base = (char *)p - (char *)head->iov_base; 181 182 rqstp->rq_res.page_len = w = nfsacl_size( 183 (resp->mask & NFS_ACL) ? resp->acl_access : NULL, 184 (resp->mask & NFS_DFACL) ? resp->acl_default : NULL); 185 while (w > 0) { 186 if (!rqstp->rq_respages[rqstp->rq_resused++]) 187 return 0; 188 w -= PAGE_SIZE; 189 } 190 191 n = nfsacl_encode(&rqstp->rq_res, base, inode, 192 resp->acl_access, 193 resp->mask & NFS_ACL, 0); 194 if (n > 0) 195 n = nfsacl_encode(&rqstp->rq_res, base + n, inode, 196 resp->acl_default, 197 resp->mask & NFS_DFACL, 198 NFS_ACL_DEFAULT); 199 if (n <= 0) 200 return 0; 201 } else 202 if (!xdr_ressize_check(rqstp, p)) 203 return 0; 204 205 return 1; 206} 207 208/* SETACL */ 209static int nfs3svc_encode_setaclres(struct svc_rqst *rqstp, __be32 *p, 210 struct nfsd3_attrstat *resp) 211{ 212 p = nfs3svc_encode_post_op_attr(rqstp, p, &resp->fh); 213 214 return xdr_ressize_check(rqstp, p); 215} 216 217/* 218 * XDR release functions 219 */ 220static int nfs3svc_release_getacl(struct svc_rqst *rqstp, __be32 *p, 221 struct nfsd3_getaclres *resp) 222{ 223 fh_put(&resp->fh); 224 posix_acl_release(resp->acl_access); 225 posix_acl_release(resp->acl_default); 226 return 1; 227} 228 229#define nfs3svc_decode_voidargs NULL 230#define nfs3svc_release_void NULL 231#define nfsd3_setaclres nfsd3_attrstat 232#define nfsd3_voidres nfsd3_voidargs 233struct nfsd3_voidargs { int dummy; }; 234 235#define PROC(name, argt, rest, relt, cache, respsize) \ 236 { (svc_procfunc) nfsd3_proc_##name, \ 237 (kxdrproc_t) nfs3svc_decode_##argt##args, \ 238 (kxdrproc_t) nfs3svc_encode_##rest##res, \ 239 (kxdrproc_t) nfs3svc_release_##relt, \ 240 sizeof(struct nfsd3_##argt##args), \ 241 sizeof(struct nfsd3_##rest##res), \ 242 0, \ 243 cache, \ 244 respsize, \ 245 } 246 247#define ST 1 /* status*/ 248#define AT 21 /* attributes */ 249#define pAT (1+AT) /* post attributes - conditional */ 250#define ACL (1+NFS_ACL_MAX_ENTRIES*3) /* Access Control List */ 251 252static struct svc_procedure nfsd_acl_procedures3[] = { 253 PROC(null, void, void, void, RC_NOCACHE, ST), 254 PROC(getacl, getacl, getacl, getacl, RC_NOCACHE, ST+1+2*(1+ACL)), 255 PROC(setacl, setacl, setacl, fhandle, RC_NOCACHE, ST+pAT), 256}; 257 258struct svc_version nfsd_acl_version3 = { 259 .vs_vers = 3, 260 .vs_nproc = 3, 261 .vs_proc = nfsd_acl_procedures3, 262 .vs_dispatch = nfsd_dispatch, 263 .vs_xdrsize = NFS3_SVC_XDRSIZE, 264 .vs_hidden = 0, 265}; 266