1 /* 2 * linux/fs/nfsd/nfs2acl.c 3 * 4 * Process version 2 NFSACL requests. 5 * 6 * Copyright (C) 2002-2003 Andreas Gruenbacher <agruen@suse.de> 7 */ 8 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> 17 18 #define NFSDDBG_FACILITY NFSDDBG_PROC 19 #define RETURN_STATUS(st) { resp->status = (st); return (st); } 20 21 /* 22 * NULL call. 23 */ 24 static __be32 25 nfsacld_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) 26 { 27 return nfs_ok; 28 } 29 30 /* 31 * Get the Access and/or Default ACL of a file. 32 */ 33 static __be32 nfsacld_proc_getacl(struct svc_rqst * rqstp, 34 struct nfsd3_getaclargs *argp, struct nfsd3_getaclres *resp) 35 { 36 svc_fh *fh; 37 struct posix_acl *acl; 38 __be32 nfserr = 0; 39 40 dprintk("nfsd: GETACL(2acl) %s\n", SVCFH_fmt(&argp->fh)); 41 42 fh = fh_copy(&resp->fh, &argp->fh); 43 nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP); 44 if (nfserr) 45 RETURN_STATUS(nfserr); 46 47 if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT)) 48 RETURN_STATUS(nfserr_inval); 49 resp->mask = argp->mask; 50 51 if (resp->mask & (NFS_ACL|NFS_ACLCNT)) { 52 acl = nfsd_get_posix_acl(fh, ACL_TYPE_ACCESS); 53 if (IS_ERR(acl)) { 54 int err = PTR_ERR(acl); 55 56 if (err == -ENODATA || err == -EOPNOTSUPP) 57 acl = NULL; 58 else { 59 nfserr = nfserrno(err); 60 goto fail; 61 } 62 } 63 if (acl == NULL) { 64 /* Solaris returns the inode's minimum ACL. */ 65 66 struct inode *inode = fh->fh_dentry->d_inode; 67 acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL); 68 } 69 resp->acl_access = acl; 70 } 71 if (resp->mask & (NFS_DFACL|NFS_DFACLCNT)) { 72 /* Check how Solaris handles requests for the Default ACL 73 of a non-directory! */ 74 75 acl = nfsd_get_posix_acl(fh, ACL_TYPE_DEFAULT); 76 if (IS_ERR(acl)) { 77 int err = PTR_ERR(acl); 78 79 if (err == -ENODATA || err == -EOPNOTSUPP) 80 acl = NULL; 81 else { 82 nfserr = nfserrno(err); 83 goto fail; 84 } 85 } 86 resp->acl_default = acl; 87 } 88 89 /* resp->acl_{access,default} are released in nfssvc_release_getacl. */ 90 RETURN_STATUS(0); 91 92 fail: 93 posix_acl_release(resp->acl_access); 94 posix_acl_release(resp->acl_default); 95 RETURN_STATUS(nfserr); 96 } 97 98 /* 99 * Set the Access and/or Default ACL of a file. 100 */ 101 static __be32 nfsacld_proc_setacl(struct svc_rqst * rqstp, 102 struct nfsd3_setaclargs *argp, 103 struct nfsd_attrstat *resp) 104 { 105 svc_fh *fh; 106 __be32 nfserr = 0; 107 108 dprintk("nfsd: SETACL(2acl) %s\n", SVCFH_fmt(&argp->fh)); 109 110 fh = fh_copy(&resp->fh, &argp->fh); 111 nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_SATTR); 112 113 if (!nfserr) { 114 nfserr = nfserrno( nfsd_set_posix_acl( 115 fh, ACL_TYPE_ACCESS, argp->acl_access) ); 116 } 117 if (!nfserr) { 118 nfserr = nfserrno( nfsd_set_posix_acl( 119 fh, ACL_TYPE_DEFAULT, argp->acl_default) ); 120 } 121 122 /* argp->acl_{access,default} may have been allocated in 123 nfssvc_decode_setaclargs. */ 124 posix_acl_release(argp->acl_access); 125 posix_acl_release(argp->acl_default); 126 return nfserr; 127 } 128 129 /* 130 * Check file attributes 131 */ 132 static __be32 nfsacld_proc_getattr(struct svc_rqst * rqstp, 133 struct nfsd_fhandle *argp, struct nfsd_attrstat *resp) 134 { 135 dprintk("nfsd: GETATTR %s\n", SVCFH_fmt(&argp->fh)); 136 137 fh_copy(&resp->fh, &argp->fh); 138 return fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP); 139 } 140 141 /* 142 * Check file access 143 */ 144 static __be32 nfsacld_proc_access(struct svc_rqst *rqstp, struct nfsd3_accessargs *argp, 145 struct nfsd3_accessres *resp) 146 { 147 __be32 nfserr; 148 149 dprintk("nfsd: ACCESS(2acl) %s 0x%x\n", 150 SVCFH_fmt(&argp->fh), 151 argp->access); 152 153 fh_copy(&resp->fh, &argp->fh); 154 resp->access = argp->access; 155 nfserr = nfsd_access(rqstp, &resp->fh, &resp->access, NULL); 156 return nfserr; 157 } 158 159 /* 160 * XDR decode functions 161 */ 162 static int nfsaclsvc_decode_getaclargs(struct svc_rqst *rqstp, __be32 *p, 163 struct nfsd3_getaclargs *argp) 164 { 165 if (!(p = nfs2svc_decode_fh(p, &argp->fh))) 166 return 0; 167 argp->mask = ntohl(*p); p++; 168 169 return xdr_argsize_check(rqstp, p); 170 } 171 172 173 static int nfsaclsvc_decode_setaclargs(struct svc_rqst *rqstp, __be32 *p, 174 struct nfsd3_setaclargs *argp) 175 { 176 struct kvec *head = rqstp->rq_arg.head; 177 unsigned int base; 178 int n; 179 180 if (!(p = nfs2svc_decode_fh(p, &argp->fh))) 181 return 0; 182 argp->mask = ntohl(*p++); 183 if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT) || 184 !xdr_argsize_check(rqstp, p)) 185 return 0; 186 187 base = (char *)p - (char *)head->iov_base; 188 n = nfsacl_decode(&rqstp->rq_arg, base, NULL, 189 (argp->mask & NFS_ACL) ? 190 &argp->acl_access : NULL); 191 if (n > 0) 192 n = nfsacl_decode(&rqstp->rq_arg, base + n, NULL, 193 (argp->mask & NFS_DFACL) ? 194 &argp->acl_default : NULL); 195 return (n > 0); 196 } 197 198 static int nfsaclsvc_decode_fhandleargs(struct svc_rqst *rqstp, __be32 *p, 199 struct nfsd_fhandle *argp) 200 { 201 if (!(p = nfs2svc_decode_fh(p, &argp->fh))) 202 return 0; 203 return xdr_argsize_check(rqstp, p); 204 } 205 206 static int nfsaclsvc_decode_accessargs(struct svc_rqst *rqstp, __be32 *p, 207 struct nfsd3_accessargs *argp) 208 { 209 if (!(p = nfs2svc_decode_fh(p, &argp->fh))) 210 return 0; 211 argp->access = ntohl(*p++); 212 213 return xdr_argsize_check(rqstp, p); 214 } 215 216 /* 217 * XDR encode functions 218 */ 219 220 /* GETACL */ 221 static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p, 222 struct nfsd3_getaclres *resp) 223 { 224 struct dentry *dentry = resp->fh.fh_dentry; 225 struct inode *inode; 226 struct kvec *head = rqstp->rq_res.head; 227 unsigned int base; 228 int n; 229 int w; 230 231 /* 232 * Since this is version 2, the check for nfserr in 233 * nfsd_dispatch actually ensures the following cannot happen. 234 * However, it seems fragile to depend on that. 235 */ 236 if (dentry == NULL || dentry->d_inode == NULL) 237 return 0; 238 inode = dentry->d_inode; 239 240 p = nfs2svc_encode_fattr(rqstp, p, &resp->fh); 241 *p++ = htonl(resp->mask); 242 if (!xdr_ressize_check(rqstp, p)) 243 return 0; 244 base = (char *)p - (char *)head->iov_base; 245 246 rqstp->rq_res.page_len = w = nfsacl_size( 247 (resp->mask & NFS_ACL) ? resp->acl_access : NULL, 248 (resp->mask & NFS_DFACL) ? resp->acl_default : NULL); 249 while (w > 0) { 250 if (!rqstp->rq_respages[rqstp->rq_resused++]) 251 return 0; 252 w -= PAGE_SIZE; 253 } 254 255 n = nfsacl_encode(&rqstp->rq_res, base, inode, 256 resp->acl_access, 257 resp->mask & NFS_ACL, 0); 258 if (n > 0) 259 n = nfsacl_encode(&rqstp->rq_res, base + n, inode, 260 resp->acl_default, 261 resp->mask & NFS_DFACL, 262 NFS_ACL_DEFAULT); 263 if (n <= 0) 264 return 0; 265 return 1; 266 } 267 268 static int nfsaclsvc_encode_attrstatres(struct svc_rqst *rqstp, __be32 *p, 269 struct nfsd_attrstat *resp) 270 { 271 p = nfs2svc_encode_fattr(rqstp, p, &resp->fh); 272 return xdr_ressize_check(rqstp, p); 273 } 274 275 /* ACCESS */ 276 static int nfsaclsvc_encode_accessres(struct svc_rqst *rqstp, __be32 *p, 277 struct nfsd3_accessres *resp) 278 { 279 p = nfs2svc_encode_fattr(rqstp, p, &resp->fh); 280 *p++ = htonl(resp->access); 281 return xdr_ressize_check(rqstp, p); 282 } 283 284 /* 285 * XDR release functions 286 */ 287 static int nfsaclsvc_release_getacl(struct svc_rqst *rqstp, __be32 *p, 288 struct nfsd3_getaclres *resp) 289 { 290 fh_put(&resp->fh); 291 posix_acl_release(resp->acl_access); 292 posix_acl_release(resp->acl_default); 293 return 1; 294 } 295 296 static int nfsaclsvc_release_attrstat(struct svc_rqst *rqstp, __be32 *p, 297 struct nfsd_attrstat *resp) 298 { 299 fh_put(&resp->fh); 300 return 1; 301 } 302 303 static int nfsaclsvc_release_access(struct svc_rqst *rqstp, __be32 *p, 304 struct nfsd3_accessres *resp) 305 { 306 fh_put(&resp->fh); 307 return 1; 308 } 309 310 #define nfsaclsvc_decode_voidargs NULL 311 #define nfsaclsvc_encode_voidres NULL 312 #define nfsaclsvc_release_void NULL 313 #define nfsd3_fhandleargs nfsd_fhandle 314 #define nfsd3_attrstatres nfsd_attrstat 315 #define nfsd3_voidres nfsd3_voidargs 316 struct nfsd3_voidargs { int dummy; }; 317 318 #define PROC(name, argt, rest, relt, cache, respsize) \ 319 { (svc_procfunc) nfsacld_proc_##name, \ 320 (kxdrproc_t) nfsaclsvc_decode_##argt##args, \ 321 (kxdrproc_t) nfsaclsvc_encode_##rest##res, \ 322 (kxdrproc_t) nfsaclsvc_release_##relt, \ 323 sizeof(struct nfsd3_##argt##args), \ 324 sizeof(struct nfsd3_##rest##res), \ 325 0, \ 326 cache, \ 327 respsize, \ 328 } 329 330 #define ST 1 /* status*/ 331 #define AT 21 /* attributes */ 332 #define pAT (1+AT) /* post attributes - conditional */ 333 #define ACL (1+NFS_ACL_MAX_ENTRIES*3) /* Access Control List */ 334 335 static struct svc_procedure nfsd_acl_procedures2[] = { 336 PROC(null, void, void, void, RC_NOCACHE, ST), 337 PROC(getacl, getacl, getacl, getacl, RC_NOCACHE, ST+1+2*(1+ACL)), 338 PROC(setacl, setacl, attrstat, attrstat, RC_NOCACHE, ST+AT), 339 PROC(getattr, fhandle, attrstat, attrstat, RC_NOCACHE, ST+AT), 340 PROC(access, access, access, access, RC_NOCACHE, ST+AT+1), 341 }; 342 343 struct svc_version nfsd_acl_version2 = { 344 .vs_vers = 2, 345 .vs_nproc = 5, 346 .vs_proc = nfsd_acl_procedures2, 347 .vs_dispatch = nfsd_dispatch, 348 .vs_xdrsize = NFS3_SVC_XDRSIZE, 349 .vs_hidden = 1, 350 }; 351