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 "cache.h" 11 #include "xdr3.h" 12 #include "vfs.h" 13 14 #define NFSDDBG_FACILITY NFSDDBG_PROC 15 #define RETURN_STATUS(st) { resp->status = (st); return (st); } 16 17 /* 18 * NULL call. 19 */ 20 static __be32 21 nfsacld_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) 22 { 23 return nfs_ok; 24 } 25 26 /* 27 * Get the Access and/or Default ACL of a file. 28 */ 29 static __be32 nfsacld_proc_getacl(struct svc_rqst * rqstp, 30 struct nfsd3_getaclargs *argp, struct nfsd3_getaclres *resp) 31 { 32 svc_fh *fh; 33 struct posix_acl *acl; 34 __be32 nfserr = 0; 35 36 dprintk("nfsd: GETACL(2acl) %s\n", SVCFH_fmt(&argp->fh)); 37 38 fh = fh_copy(&resp->fh, &argp->fh); 39 nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP); 40 if (nfserr) 41 RETURN_STATUS(nfserr); 42 43 if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT)) 44 RETURN_STATUS(nfserr_inval); 45 resp->mask = argp->mask; 46 47 if (resp->mask & (NFS_ACL|NFS_ACLCNT)) { 48 acl = nfsd_get_posix_acl(fh, ACL_TYPE_ACCESS); 49 if (IS_ERR(acl)) { 50 int err = PTR_ERR(acl); 51 52 if (err == -ENODATA || err == -EOPNOTSUPP) 53 acl = NULL; 54 else { 55 nfserr = nfserrno(err); 56 goto fail; 57 } 58 } 59 if (acl == NULL) { 60 /* Solaris returns the inode's minimum ACL. */ 61 62 struct inode *inode = fh->fh_dentry->d_inode; 63 acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL); 64 } 65 resp->acl_access = acl; 66 } 67 if (resp->mask & (NFS_DFACL|NFS_DFACLCNT)) { 68 /* Check how Solaris handles requests for the Default ACL 69 of a non-directory! */ 70 71 acl = nfsd_get_posix_acl(fh, ACL_TYPE_DEFAULT); 72 if (IS_ERR(acl)) { 73 int err = PTR_ERR(acl); 74 75 if (err == -ENODATA || err == -EOPNOTSUPP) 76 acl = NULL; 77 else { 78 nfserr = nfserrno(err); 79 goto fail; 80 } 81 } 82 resp->acl_default = acl; 83 } 84 85 /* resp->acl_{access,default} are released in nfssvc_release_getacl. */ 86 RETURN_STATUS(0); 87 88 fail: 89 posix_acl_release(resp->acl_access); 90 posix_acl_release(resp->acl_default); 91 RETURN_STATUS(nfserr); 92 } 93 94 /* 95 * Set the Access and/or Default ACL of a file. 96 */ 97 static __be32 nfsacld_proc_setacl(struct svc_rqst * rqstp, 98 struct nfsd3_setaclargs *argp, 99 struct nfsd_attrstat *resp) 100 { 101 svc_fh *fh; 102 __be32 nfserr = 0; 103 104 dprintk("nfsd: SETACL(2acl) %s\n", SVCFH_fmt(&argp->fh)); 105 106 fh = fh_copy(&resp->fh, &argp->fh); 107 nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_SATTR); 108 109 if (!nfserr) { 110 nfserr = nfserrno( nfsd_set_posix_acl( 111 fh, ACL_TYPE_ACCESS, argp->acl_access) ); 112 } 113 if (!nfserr) { 114 nfserr = nfserrno( nfsd_set_posix_acl( 115 fh, ACL_TYPE_DEFAULT, argp->acl_default) ); 116 } 117 118 /* argp->acl_{access,default} may have been allocated in 119 nfssvc_decode_setaclargs. */ 120 posix_acl_release(argp->acl_access); 121 posix_acl_release(argp->acl_default); 122 return nfserr; 123 } 124 125 /* 126 * Check file attributes 127 */ 128 static __be32 nfsacld_proc_getattr(struct svc_rqst * rqstp, 129 struct nfsd_fhandle *argp, struct nfsd_attrstat *resp) 130 { 131 dprintk("nfsd: GETATTR %s\n", SVCFH_fmt(&argp->fh)); 132 133 fh_copy(&resp->fh, &argp->fh); 134 return fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP); 135 } 136 137 /* 138 * Check file access 139 */ 140 static __be32 nfsacld_proc_access(struct svc_rqst *rqstp, struct nfsd3_accessargs *argp, 141 struct nfsd3_accessres *resp) 142 { 143 __be32 nfserr; 144 145 dprintk("nfsd: ACCESS(2acl) %s 0x%x\n", 146 SVCFH_fmt(&argp->fh), 147 argp->access); 148 149 fh_copy(&resp->fh, &argp->fh); 150 resp->access = argp->access; 151 nfserr = nfsd_access(rqstp, &resp->fh, &resp->access, NULL); 152 return nfserr; 153 } 154 155 /* 156 * XDR decode functions 157 */ 158 static int nfsaclsvc_decode_getaclargs(struct svc_rqst *rqstp, __be32 *p, 159 struct nfsd3_getaclargs *argp) 160 { 161 if (!(p = nfs2svc_decode_fh(p, &argp->fh))) 162 return 0; 163 argp->mask = ntohl(*p); p++; 164 165 return xdr_argsize_check(rqstp, p); 166 } 167 168 169 static int nfsaclsvc_decode_setaclargs(struct svc_rqst *rqstp, __be32 *p, 170 struct nfsd3_setaclargs *argp) 171 { 172 struct kvec *head = rqstp->rq_arg.head; 173 unsigned int base; 174 int n; 175 176 if (!(p = nfs2svc_decode_fh(p, &argp->fh))) 177 return 0; 178 argp->mask = ntohl(*p++); 179 if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT) || 180 !xdr_argsize_check(rqstp, p)) 181 return 0; 182 183 base = (char *)p - (char *)head->iov_base; 184 n = nfsacl_decode(&rqstp->rq_arg, base, NULL, 185 (argp->mask & NFS_ACL) ? 186 &argp->acl_access : NULL); 187 if (n > 0) 188 n = nfsacl_decode(&rqstp->rq_arg, base + n, NULL, 189 (argp->mask & NFS_DFACL) ? 190 &argp->acl_default : NULL); 191 return (n > 0); 192 } 193 194 static int nfsaclsvc_decode_fhandleargs(struct svc_rqst *rqstp, __be32 *p, 195 struct nfsd_fhandle *argp) 196 { 197 if (!(p = nfs2svc_decode_fh(p, &argp->fh))) 198 return 0; 199 return xdr_argsize_check(rqstp, p); 200 } 201 202 static int nfsaclsvc_decode_accessargs(struct svc_rqst *rqstp, __be32 *p, 203 struct nfsd3_accessargs *argp) 204 { 205 if (!(p = nfs2svc_decode_fh(p, &argp->fh))) 206 return 0; 207 argp->access = ntohl(*p++); 208 209 return xdr_argsize_check(rqstp, p); 210 } 211 212 /* 213 * XDR encode functions 214 */ 215 216 /* 217 * There must be an encoding function for void results so svc_process 218 * will work properly. 219 */ 220 int 221 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_respages[rqstp->rq_resused++]) 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