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 int 222 nfsaclsvc_encode_voidres(struct svc_rqst *rqstp, __be32 *p, void *dummy) 223 { 224 return xdr_ressize_check(rqstp, p); 225 } 226 227 /* GETACL */ 228 static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p, 229 struct nfsd3_getaclres *resp) 230 { 231 struct dentry *dentry = resp->fh.fh_dentry; 232 struct inode *inode; 233 struct kvec *head = rqstp->rq_res.head; 234 unsigned int base; 235 int n; 236 int w; 237 238 /* 239 * Since this is version 2, the check for nfserr in 240 * nfsd_dispatch actually ensures the following cannot happen. 241 * However, it seems fragile to depend on that. 242 */ 243 if (dentry == NULL || dentry->d_inode == NULL) 244 return 0; 245 inode = dentry->d_inode; 246 247 p = nfs2svc_encode_fattr(rqstp, p, &resp->fh); 248 *p++ = htonl(resp->mask); 249 if (!xdr_ressize_check(rqstp, p)) 250 return 0; 251 base = (char *)p - (char *)head->iov_base; 252 253 rqstp->rq_res.page_len = w = nfsacl_size( 254 (resp->mask & NFS_ACL) ? resp->acl_access : NULL, 255 (resp->mask & NFS_DFACL) ? resp->acl_default : NULL); 256 while (w > 0) { 257 if (!rqstp->rq_respages[rqstp->rq_resused++]) 258 return 0; 259 w -= PAGE_SIZE; 260 } 261 262 n = nfsacl_encode(&rqstp->rq_res, base, inode, 263 resp->acl_access, 264 resp->mask & NFS_ACL, 0); 265 if (n > 0) 266 n = nfsacl_encode(&rqstp->rq_res, base + n, inode, 267 resp->acl_default, 268 resp->mask & NFS_DFACL, 269 NFS_ACL_DEFAULT); 270 if (n <= 0) 271 return 0; 272 return 1; 273 } 274 275 static int nfsaclsvc_encode_attrstatres(struct svc_rqst *rqstp, __be32 *p, 276 struct nfsd_attrstat *resp) 277 { 278 p = nfs2svc_encode_fattr(rqstp, p, &resp->fh); 279 return xdr_ressize_check(rqstp, p); 280 } 281 282 /* ACCESS */ 283 static int nfsaclsvc_encode_accessres(struct svc_rqst *rqstp, __be32 *p, 284 struct nfsd3_accessres *resp) 285 { 286 p = nfs2svc_encode_fattr(rqstp, p, &resp->fh); 287 *p++ = htonl(resp->access); 288 return xdr_ressize_check(rqstp, p); 289 } 290 291 /* 292 * XDR release functions 293 */ 294 static int nfsaclsvc_release_getacl(struct svc_rqst *rqstp, __be32 *p, 295 struct nfsd3_getaclres *resp) 296 { 297 fh_put(&resp->fh); 298 posix_acl_release(resp->acl_access); 299 posix_acl_release(resp->acl_default); 300 return 1; 301 } 302 303 static int nfsaclsvc_release_attrstat(struct svc_rqst *rqstp, __be32 *p, 304 struct nfsd_attrstat *resp) 305 { 306 fh_put(&resp->fh); 307 return 1; 308 } 309 310 static int nfsaclsvc_release_access(struct svc_rqst *rqstp, __be32 *p, 311 struct nfsd3_accessres *resp) 312 { 313 fh_put(&resp->fh); 314 return 1; 315 } 316 317 #define nfsaclsvc_decode_voidargs NULL 318 #define nfsaclsvc_release_void NULL 319 #define nfsd3_fhandleargs nfsd_fhandle 320 #define nfsd3_attrstatres nfsd_attrstat 321 #define nfsd3_voidres nfsd3_voidargs 322 struct nfsd3_voidargs { int dummy; }; 323 324 #define PROC(name, argt, rest, relt, cache, respsize) \ 325 { (svc_procfunc) nfsacld_proc_##name, \ 326 (kxdrproc_t) nfsaclsvc_decode_##argt##args, \ 327 (kxdrproc_t) nfsaclsvc_encode_##rest##res, \ 328 (kxdrproc_t) nfsaclsvc_release_##relt, \ 329 sizeof(struct nfsd3_##argt##args), \ 330 sizeof(struct nfsd3_##rest##res), \ 331 0, \ 332 cache, \ 333 respsize, \ 334 } 335 336 #define ST 1 /* status*/ 337 #define AT 21 /* attributes */ 338 #define pAT (1+AT) /* post attributes - conditional */ 339 #define ACL (1+NFS_ACL_MAX_ENTRIES*3) /* Access Control List */ 340 341 static struct svc_procedure nfsd_acl_procedures2[] = { 342 PROC(null, void, void, void, RC_NOCACHE, ST), 343 PROC(getacl, getacl, getacl, getacl, RC_NOCACHE, ST+1+2*(1+ACL)), 344 PROC(setacl, setacl, attrstat, attrstat, RC_NOCACHE, ST+AT), 345 PROC(getattr, fhandle, attrstat, attrstat, RC_NOCACHE, ST+AT), 346 PROC(access, access, access, access, RC_NOCACHE, ST+AT+1), 347 }; 348 349 struct svc_version nfsd_acl_version2 = { 350 .vs_vers = 2, 351 .vs_nproc = 5, 352 .vs_proc = nfsd_acl_procedures2, 353 .vs_dispatch = nfsd_dispatch, 354 .vs_xdrsize = NFS3_SVC_XDRSIZE, 355 .vs_hidden = 0, 356 }; 357