1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Process version 2 NFSACL requests. 4 * 5 * Copyright (C) 2002-2003 Andreas Gruenbacher <agruen@suse.de> 6 */ 7 8 #include "nfsd.h" 9 /* FIXME: nfsacl.h is a broken header */ 10 #include <linux/nfsacl.h> 11 #include <linux/gfp.h> 12 #include "cache.h" 13 #include "xdr3.h" 14 #include "vfs.h" 15 16 #define NFSDDBG_FACILITY NFSDDBG_PROC 17 18 /* 19 * NULL call. 20 */ 21 static __be32 22 nfsacld_proc_null(struct svc_rqst *rqstp) 23 { 24 return rpc_success; 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 { 32 struct nfsd3_getaclargs *argp = rqstp->rq_argp; 33 struct nfsd3_getaclres *resp = rqstp->rq_resp; 34 struct posix_acl *acl; 35 struct inode *inode; 36 svc_fh *fh; 37 38 dprintk("nfsd: GETACL(2acl) %s\n", SVCFH_fmt(&argp->fh)); 39 40 fh = fh_copy(&resp->fh, &argp->fh); 41 resp->status = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP); 42 if (resp->status != nfs_ok) 43 goto out; 44 45 inode = d_inode(fh->fh_dentry); 46 47 if (argp->mask & ~NFS_ACL_MASK) { 48 resp->status = nfserr_io; 49 goto out; 50 } 51 resp->mask = argp->mask; 52 53 resp->status = fh_getattr(fh, &resp->stat); 54 if (resp->status != nfs_ok) 55 goto out; 56 57 if (resp->mask & (NFS_ACL|NFS_ACLCNT)) { 58 acl = get_inode_acl(inode, ACL_TYPE_ACCESS); 59 if (acl == NULL) { 60 /* Solaris returns the inode's minimum ACL. */ 61 acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL); 62 } 63 if (IS_ERR(acl)) { 64 resp->status = nfserrno(PTR_ERR(acl)); 65 goto fail; 66 } 67 resp->acl_access = acl; 68 } 69 if (resp->mask & (NFS_DFACL|NFS_DFACLCNT)) { 70 /* Check how Solaris handles requests for the Default ACL 71 of a non-directory! */ 72 acl = get_inode_acl(inode, ACL_TYPE_DEFAULT); 73 if (IS_ERR(acl)) { 74 resp->status = nfserrno(PTR_ERR(acl)); 75 goto fail; 76 } 77 resp->acl_default = acl; 78 } 79 80 /* resp->acl_{access,default} are released in nfssvc_release_getacl. */ 81 out: 82 return rpc_success; 83 84 fail: 85 posix_acl_release(resp->acl_access); 86 posix_acl_release(resp->acl_default); 87 resp->acl_access = NULL; 88 resp->acl_default = NULL; 89 goto out; 90 } 91 92 /* 93 * Set the Access and/or Default ACL of a file. 94 */ 95 static __be32 nfsacld_proc_setacl(struct svc_rqst *rqstp) 96 { 97 struct nfsd3_setaclargs *argp = rqstp->rq_argp; 98 struct nfsd_attrstat *resp = rqstp->rq_resp; 99 struct inode *inode; 100 svc_fh *fh; 101 int error; 102 103 dprintk("nfsd: SETACL(2acl) %s\n", SVCFH_fmt(&argp->fh)); 104 105 fh = fh_copy(&resp->fh, &argp->fh); 106 resp->status = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_SATTR); 107 if (resp->status != nfs_ok) 108 goto out; 109 110 inode = d_inode(fh->fh_dentry); 111 112 error = fh_want_write(fh); 113 if (error) 114 goto out_errno; 115 116 inode_lock(inode); 117 118 error = set_posix_acl(&nop_mnt_idmap, fh->fh_dentry, ACL_TYPE_ACCESS, 119 argp->acl_access); 120 if (error) 121 goto out_drop_lock; 122 error = set_posix_acl(&nop_mnt_idmap, fh->fh_dentry, ACL_TYPE_DEFAULT, 123 argp->acl_default); 124 if (error) 125 goto out_drop_lock; 126 127 inode_unlock(inode); 128 129 fh_drop_write(fh); 130 131 resp->status = fh_getattr(fh, &resp->stat); 132 133 out: 134 /* argp->acl_{access,default} are released in nfsaclsvc_release_setacl. */ 135 return rpc_success; 136 137 out_drop_lock: 138 inode_unlock(inode); 139 fh_drop_write(fh); 140 out_errno: 141 resp->status = nfserrno(error); 142 goto out; 143 } 144 145 /* 146 * Check file attributes 147 */ 148 static __be32 nfsacld_proc_getattr(struct svc_rqst *rqstp) 149 { 150 struct nfsd_fhandle *argp = rqstp->rq_argp; 151 struct nfsd_attrstat *resp = rqstp->rq_resp; 152 153 dprintk("nfsd: GETATTR %s\n", SVCFH_fmt(&argp->fh)); 154 155 fh_copy(&resp->fh, &argp->fh); 156 resp->status = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP); 157 if (resp->status != nfs_ok) 158 goto out; 159 resp->status = fh_getattr(&resp->fh, &resp->stat); 160 out: 161 return rpc_success; 162 } 163 164 /* 165 * Check file access 166 */ 167 static __be32 nfsacld_proc_access(struct svc_rqst *rqstp) 168 { 169 struct nfsd3_accessargs *argp = rqstp->rq_argp; 170 struct nfsd3_accessres *resp = rqstp->rq_resp; 171 172 dprintk("nfsd: ACCESS(2acl) %s 0x%x\n", 173 SVCFH_fmt(&argp->fh), 174 argp->access); 175 176 fh_copy(&resp->fh, &argp->fh); 177 resp->access = argp->access; 178 resp->status = nfsd_access(rqstp, &resp->fh, &resp->access, NULL); 179 if (resp->status != nfs_ok) 180 goto out; 181 resp->status = fh_getattr(&resp->fh, &resp->stat); 182 out: 183 return rpc_success; 184 } 185 186 /* 187 * XDR decode functions 188 */ 189 190 static bool 191 nfsaclsvc_decode_getaclargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) 192 { 193 struct nfsd3_getaclargs *argp = rqstp->rq_argp; 194 195 if (!svcxdr_decode_fhandle(xdr, &argp->fh)) 196 return false; 197 if (xdr_stream_decode_u32(xdr, &argp->mask) < 0) 198 return false; 199 200 return true; 201 } 202 203 static bool 204 nfsaclsvc_decode_setaclargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) 205 { 206 struct nfsd3_setaclargs *argp = rqstp->rq_argp; 207 208 if (!svcxdr_decode_fhandle(xdr, &argp->fh)) 209 return false; 210 if (xdr_stream_decode_u32(xdr, &argp->mask) < 0) 211 return false; 212 if (argp->mask & ~NFS_ACL_MASK) 213 return false; 214 if (!nfs_stream_decode_acl(xdr, NULL, (argp->mask & NFS_ACL) ? 215 &argp->acl_access : NULL)) 216 return false; 217 if (!nfs_stream_decode_acl(xdr, NULL, (argp->mask & NFS_DFACL) ? 218 &argp->acl_default : NULL)) 219 return false; 220 221 return true; 222 } 223 224 static bool 225 nfsaclsvc_decode_accessargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) 226 { 227 struct nfsd3_accessargs *args = rqstp->rq_argp; 228 229 if (!svcxdr_decode_fhandle(xdr, &args->fh)) 230 return false; 231 if (xdr_stream_decode_u32(xdr, &args->access) < 0) 232 return false; 233 234 return true; 235 } 236 237 /* 238 * XDR encode functions 239 */ 240 241 /* GETACL */ 242 static bool 243 nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, struct xdr_stream *xdr) 244 { 245 struct nfsd3_getaclres *resp = rqstp->rq_resp; 246 struct dentry *dentry = resp->fh.fh_dentry; 247 struct inode *inode; 248 249 if (!svcxdr_encode_stat(xdr, resp->status)) 250 return false; 251 252 if (dentry == NULL || d_really_is_negative(dentry)) 253 return true; 254 inode = d_inode(dentry); 255 256 if (!svcxdr_encode_fattr(rqstp, xdr, &resp->fh, &resp->stat)) 257 return false; 258 if (xdr_stream_encode_u32(xdr, resp->mask) < 0) 259 return false; 260 261 if (!nfs_stream_encode_acl(xdr, inode, resp->acl_access, 262 resp->mask & NFS_ACL, 0)) 263 return false; 264 if (!nfs_stream_encode_acl(xdr, inode, resp->acl_default, 265 resp->mask & NFS_DFACL, NFS_ACL_DEFAULT)) 266 return false; 267 268 return true; 269 } 270 271 /* ACCESS */ 272 static bool 273 nfsaclsvc_encode_accessres(struct svc_rqst *rqstp, struct xdr_stream *xdr) 274 { 275 struct nfsd3_accessres *resp = rqstp->rq_resp; 276 277 if (!svcxdr_encode_stat(xdr, resp->status)) 278 return false; 279 switch (resp->status) { 280 case nfs_ok: 281 if (!svcxdr_encode_fattr(rqstp, xdr, &resp->fh, &resp->stat)) 282 return false; 283 if (xdr_stream_encode_u32(xdr, resp->access) < 0) 284 return false; 285 break; 286 } 287 288 return true; 289 } 290 291 /* 292 * XDR release functions 293 */ 294 static void nfsaclsvc_release_getacl(struct svc_rqst *rqstp) 295 { 296 struct nfsd3_getaclres *resp = rqstp->rq_resp; 297 298 fh_put(&resp->fh); 299 posix_acl_release(resp->acl_access); 300 posix_acl_release(resp->acl_default); 301 } 302 303 static void nfsaclsvc_release_access(struct svc_rqst *rqstp) 304 { 305 struct nfsd3_accessres *resp = rqstp->rq_resp; 306 307 fh_put(&resp->fh); 308 } 309 310 static void nfsaclsvc_release_setacl(struct svc_rqst *rqstp) 311 { 312 struct nfsd3_setaclargs *argp = rqstp->rq_argp; 313 struct nfsd_attrstat *resp = rqstp->rq_resp; 314 315 fh_put(&resp->fh); 316 posix_acl_release(argp->acl_access); 317 posix_acl_release(argp->acl_default); 318 } 319 320 #define ST 1 /* status*/ 321 #define AT 21 /* attributes */ 322 #define pAT (1+AT) /* post attributes - conditional */ 323 #define ACL (1+NFS_ACL_MAX_ENTRIES*3) /* Access Control List */ 324 325 static const struct svc_procedure nfsd_acl_procedures2[5] = { 326 [ACLPROC2_NULL] = { 327 .pc_func = nfsacld_proc_null, 328 .pc_decode = nfssvc_decode_voidarg, 329 .pc_encode = nfssvc_encode_voidres, 330 .pc_argsize = sizeof(struct nfsd_voidargs), 331 .pc_argzero = sizeof(struct nfsd_voidargs), 332 .pc_ressize = sizeof(struct nfsd_voidres), 333 .pc_cachetype = RC_NOCACHE, 334 .pc_xdrressize = ST, 335 .pc_name = "NULL", 336 }, 337 [ACLPROC2_GETACL] = { 338 .pc_func = nfsacld_proc_getacl, 339 .pc_decode = nfsaclsvc_decode_getaclargs, 340 .pc_encode = nfsaclsvc_encode_getaclres, 341 .pc_release = nfsaclsvc_release_getacl, 342 .pc_argsize = sizeof(struct nfsd3_getaclargs), 343 .pc_argzero = sizeof(struct nfsd3_getaclargs), 344 .pc_ressize = sizeof(struct nfsd3_getaclres), 345 .pc_cachetype = RC_NOCACHE, 346 .pc_xdrressize = ST+1+2*(1+ACL), 347 .pc_name = "GETACL", 348 }, 349 [ACLPROC2_SETACL] = { 350 .pc_func = nfsacld_proc_setacl, 351 .pc_decode = nfsaclsvc_decode_setaclargs, 352 .pc_encode = nfssvc_encode_attrstatres, 353 .pc_release = nfsaclsvc_release_setacl, 354 .pc_argsize = sizeof(struct nfsd3_setaclargs), 355 .pc_argzero = sizeof(struct nfsd3_setaclargs), 356 .pc_ressize = sizeof(struct nfsd_attrstat), 357 .pc_cachetype = RC_NOCACHE, 358 .pc_xdrressize = ST+AT, 359 .pc_name = "SETACL", 360 }, 361 [ACLPROC2_GETATTR] = { 362 .pc_func = nfsacld_proc_getattr, 363 .pc_decode = nfssvc_decode_fhandleargs, 364 .pc_encode = nfssvc_encode_attrstatres, 365 .pc_release = nfssvc_release_attrstat, 366 .pc_argsize = sizeof(struct nfsd_fhandle), 367 .pc_argzero = sizeof(struct nfsd_fhandle), 368 .pc_ressize = sizeof(struct nfsd_attrstat), 369 .pc_cachetype = RC_NOCACHE, 370 .pc_xdrressize = ST+AT, 371 .pc_name = "GETATTR", 372 }, 373 [ACLPROC2_ACCESS] = { 374 .pc_func = nfsacld_proc_access, 375 .pc_decode = nfsaclsvc_decode_accessargs, 376 .pc_encode = nfsaclsvc_encode_accessres, 377 .pc_release = nfsaclsvc_release_access, 378 .pc_argsize = sizeof(struct nfsd3_accessargs), 379 .pc_argzero = sizeof(struct nfsd3_accessargs), 380 .pc_ressize = sizeof(struct nfsd3_accessres), 381 .pc_cachetype = RC_NOCACHE, 382 .pc_xdrressize = ST+AT+1, 383 .pc_name = "SETATTR", 384 }, 385 }; 386 387 static DEFINE_PER_CPU_ALIGNED(unsigned long, 388 nfsd_acl_count2[ARRAY_SIZE(nfsd_acl_procedures2)]); 389 const struct svc_version nfsd_acl_version2 = { 390 .vs_vers = 2, 391 .vs_nproc = ARRAY_SIZE(nfsd_acl_procedures2), 392 .vs_proc = nfsd_acl_procedures2, 393 .vs_count = nfsd_acl_count2, 394 .vs_dispatch = nfsd_dispatch, 395 .vs_xdrsize = NFS3_SVC_XDRSIZE, 396 }; 397