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