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