Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Process version 2 NFSACL requests.
0004  *
0005  * Copyright (C) 2002-2003 Andreas Gruenbacher <agruen@suse.de>
0006  */
0007 
0008 #include "nfsd.h"
0009 /* FIXME: nfsacl.h is a broken header */
0010 #include <linux/nfsacl.h>
0011 #include <linux/gfp.h>
0012 #include "cache.h"
0013 #include "xdr3.h"
0014 #include "vfs.h"
0015 
0016 #define NFSDDBG_FACILITY        NFSDDBG_PROC
0017 
0018 /*
0019  * NULL call.
0020  */
0021 static __be32
0022 nfsacld_proc_null(struct svc_rqst *rqstp)
0023 {
0024     return rpc_success;
0025 }
0026 
0027 /*
0028  * Get the Access and/or Default ACL of a file.
0029  */
0030 static __be32 nfsacld_proc_getacl(struct svc_rqst *rqstp)
0031 {
0032     struct nfsd3_getaclargs *argp = rqstp->rq_argp;
0033     struct nfsd3_getaclres *resp = rqstp->rq_resp;
0034     struct posix_acl *acl;
0035     struct inode *inode;
0036     svc_fh *fh;
0037 
0038     dprintk("nfsd: GETACL(2acl)   %s\n", SVCFH_fmt(&argp->fh));
0039 
0040     fh = fh_copy(&resp->fh, &argp->fh);
0041     resp->status = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP);
0042     if (resp->status != nfs_ok)
0043         goto out;
0044 
0045     inode = d_inode(fh->fh_dentry);
0046 
0047     if (argp->mask & ~NFS_ACL_MASK) {
0048         resp->status = nfserr_inval;
0049         goto out;
0050     }
0051     resp->mask = argp->mask;
0052 
0053     resp->status = fh_getattr(fh, &resp->stat);
0054     if (resp->status != nfs_ok)
0055         goto out;
0056 
0057     if (resp->mask & (NFS_ACL|NFS_ACLCNT)) {
0058         acl = get_acl(inode, ACL_TYPE_ACCESS);
0059         if (acl == NULL) {
0060             /* Solaris returns the inode's minimum ACL. */
0061             acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
0062         }
0063         if (IS_ERR(acl)) {
0064             resp->status = nfserrno(PTR_ERR(acl));
0065             goto fail;
0066         }
0067         resp->acl_access = acl;
0068     }
0069     if (resp->mask & (NFS_DFACL|NFS_DFACLCNT)) {
0070         /* Check how Solaris handles requests for the Default ACL
0071            of a non-directory! */
0072         acl = get_acl(inode, ACL_TYPE_DEFAULT);
0073         if (IS_ERR(acl)) {
0074             resp->status = nfserrno(PTR_ERR(acl));
0075             goto fail;
0076         }
0077         resp->acl_default = acl;
0078     }
0079 
0080     /* resp->acl_{access,default} are released in nfssvc_release_getacl. */
0081 out:
0082     return rpc_success;
0083 
0084 fail:
0085     posix_acl_release(resp->acl_access);
0086     posix_acl_release(resp->acl_default);
0087     goto out;
0088 }
0089 
0090 /*
0091  * Set the Access and/or Default ACL of a file.
0092  */
0093 static __be32 nfsacld_proc_setacl(struct svc_rqst *rqstp)
0094 {
0095     struct nfsd3_setaclargs *argp = rqstp->rq_argp;
0096     struct nfsd_attrstat *resp = rqstp->rq_resp;
0097     struct inode *inode;
0098     svc_fh *fh;
0099     int error;
0100 
0101     dprintk("nfsd: SETACL(2acl)   %s\n", SVCFH_fmt(&argp->fh));
0102 
0103     fh = fh_copy(&resp->fh, &argp->fh);
0104     resp->status = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_SATTR);
0105     if (resp->status != nfs_ok)
0106         goto out;
0107 
0108     inode = d_inode(fh->fh_dentry);
0109 
0110     error = fh_want_write(fh);
0111     if (error)
0112         goto out_errno;
0113 
0114     inode_lock(inode);
0115 
0116     error = set_posix_acl(&init_user_ns, inode, ACL_TYPE_ACCESS,
0117                   argp->acl_access);
0118     if (error)
0119         goto out_drop_lock;
0120     error = set_posix_acl(&init_user_ns, inode, ACL_TYPE_DEFAULT,
0121                   argp->acl_default);
0122     if (error)
0123         goto out_drop_lock;
0124 
0125     inode_unlock(inode);
0126 
0127     fh_drop_write(fh);
0128 
0129     resp->status = fh_getattr(fh, &resp->stat);
0130 
0131 out:
0132     /* argp->acl_{access,default} may have been allocated in
0133        nfssvc_decode_setaclargs. */
0134     posix_acl_release(argp->acl_access);
0135     posix_acl_release(argp->acl_default);
0136     return rpc_success;
0137 
0138 out_drop_lock:
0139     inode_unlock(inode);
0140     fh_drop_write(fh);
0141 out_errno:
0142     resp->status = nfserrno(error);
0143     goto out;
0144 }
0145 
0146 /*
0147  * Check file attributes
0148  */
0149 static __be32 nfsacld_proc_getattr(struct svc_rqst *rqstp)
0150 {
0151     struct nfsd_fhandle *argp = rqstp->rq_argp;
0152     struct nfsd_attrstat *resp = rqstp->rq_resp;
0153 
0154     dprintk("nfsd: GETATTR  %s\n", SVCFH_fmt(&argp->fh));
0155 
0156     fh_copy(&resp->fh, &argp->fh);
0157     resp->status = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP);
0158     if (resp->status != nfs_ok)
0159         goto out;
0160     resp->status = fh_getattr(&resp->fh, &resp->stat);
0161 out:
0162     return rpc_success;
0163 }
0164 
0165 /*
0166  * Check file access
0167  */
0168 static __be32 nfsacld_proc_access(struct svc_rqst *rqstp)
0169 {
0170     struct nfsd3_accessargs *argp = rqstp->rq_argp;
0171     struct nfsd3_accessres *resp = rqstp->rq_resp;
0172 
0173     dprintk("nfsd: ACCESS(2acl)   %s 0x%x\n",
0174             SVCFH_fmt(&argp->fh),
0175             argp->access);
0176 
0177     fh_copy(&resp->fh, &argp->fh);
0178     resp->access = argp->access;
0179     resp->status = nfsd_access(rqstp, &resp->fh, &resp->access, NULL);
0180     if (resp->status != nfs_ok)
0181         goto out;
0182     resp->status = fh_getattr(&resp->fh, &resp->stat);
0183 out:
0184     return rpc_success;
0185 }
0186 
0187 /*
0188  * XDR decode functions
0189  */
0190 
0191 static bool
0192 nfsaclsvc_decode_getaclargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
0193 {
0194     struct nfsd3_getaclargs *argp = rqstp->rq_argp;
0195 
0196     if (!svcxdr_decode_fhandle(xdr, &argp->fh))
0197         return false;
0198     if (xdr_stream_decode_u32(xdr, &argp->mask) < 0)
0199         return false;
0200 
0201     return true;
0202 }
0203 
0204 static bool
0205 nfsaclsvc_decode_setaclargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
0206 {
0207     struct nfsd3_setaclargs *argp = rqstp->rq_argp;
0208 
0209     if (!svcxdr_decode_fhandle(xdr, &argp->fh))
0210         return false;
0211     if (xdr_stream_decode_u32(xdr, &argp->mask) < 0)
0212         return false;
0213     if (argp->mask & ~NFS_ACL_MASK)
0214         return false;
0215     if (!nfs_stream_decode_acl(xdr, NULL, (argp->mask & NFS_ACL) ?
0216                    &argp->acl_access : NULL))
0217         return false;
0218     if (!nfs_stream_decode_acl(xdr, NULL, (argp->mask & NFS_DFACL) ?
0219                    &argp->acl_default : NULL))
0220         return false;
0221 
0222     return true;
0223 }
0224 
0225 static bool
0226 nfsaclsvc_decode_accessargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
0227 {
0228     struct nfsd3_accessargs *args = rqstp->rq_argp;
0229 
0230     if (!svcxdr_decode_fhandle(xdr, &args->fh))
0231         return false;
0232     if (xdr_stream_decode_u32(xdr, &args->access) < 0)
0233         return false;
0234 
0235     return true;
0236 }
0237 
0238 /*
0239  * XDR encode functions
0240  */
0241 
0242 /* GETACL */
0243 static bool
0244 nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
0245 {
0246     struct nfsd3_getaclres *resp = rqstp->rq_resp;
0247     struct dentry *dentry = resp->fh.fh_dentry;
0248     struct inode *inode;
0249     int w;
0250 
0251     if (!svcxdr_encode_stat(xdr, resp->status))
0252         return false;
0253 
0254     if (dentry == NULL || d_really_is_negative(dentry))
0255         return true;
0256     inode = d_inode(dentry);
0257 
0258     if (!svcxdr_encode_fattr(rqstp, xdr, &resp->fh, &resp->stat))
0259         return false;
0260     if (xdr_stream_encode_u32(xdr, resp->mask) < 0)
0261         return false;
0262 
0263     rqstp->rq_res.page_len = w = nfsacl_size(
0264         (resp->mask & NFS_ACL)   ? resp->acl_access  : NULL,
0265         (resp->mask & NFS_DFACL) ? resp->acl_default : NULL);
0266     while (w > 0) {
0267         if (!*(rqstp->rq_next_page++))
0268             return true;
0269         w -= PAGE_SIZE;
0270     }
0271 
0272     if (!nfs_stream_encode_acl(xdr, inode, resp->acl_access,
0273                    resp->mask & NFS_ACL, 0))
0274         return false;
0275     if (!nfs_stream_encode_acl(xdr, inode, resp->acl_default,
0276                    resp->mask & NFS_DFACL, NFS_ACL_DEFAULT))
0277         return false;
0278 
0279     return true;
0280 }
0281 
0282 /* ACCESS */
0283 static bool
0284 nfsaclsvc_encode_accessres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
0285 {
0286     struct nfsd3_accessres *resp = rqstp->rq_resp;
0287 
0288     if (!svcxdr_encode_stat(xdr, resp->status))
0289         return false;
0290     switch (resp->status) {
0291     case nfs_ok:
0292         if (!svcxdr_encode_fattr(rqstp, xdr, &resp->fh, &resp->stat))
0293             return false;
0294         if (xdr_stream_encode_u32(xdr, resp->access) < 0)
0295             return false;
0296         break;
0297     }
0298 
0299     return true;
0300 }
0301 
0302 /*
0303  * XDR release functions
0304  */
0305 static void nfsaclsvc_release_getacl(struct svc_rqst *rqstp)
0306 {
0307     struct nfsd3_getaclres *resp = rqstp->rq_resp;
0308 
0309     fh_put(&resp->fh);
0310     posix_acl_release(resp->acl_access);
0311     posix_acl_release(resp->acl_default);
0312 }
0313 
0314 static void nfsaclsvc_release_access(struct svc_rqst *rqstp)
0315 {
0316     struct nfsd3_accessres *resp = rqstp->rq_resp;
0317 
0318     fh_put(&resp->fh);
0319 }
0320 
0321 struct nfsd3_voidargs { int dummy; };
0322 
0323 #define ST 1        /* status*/
0324 #define AT 21       /* attributes */
0325 #define pAT (1+AT)  /* post attributes - conditional */
0326 #define ACL (1+NFS_ACL_MAX_ENTRIES*3)  /* Access Control List */
0327 
0328 static const struct svc_procedure nfsd_acl_procedures2[5] = {
0329     [ACLPROC2_NULL] = {
0330         .pc_func = nfsacld_proc_null,
0331         .pc_decode = nfssvc_decode_voidarg,
0332         .pc_encode = nfssvc_encode_voidres,
0333         .pc_argsize = sizeof(struct nfsd_voidargs),
0334         .pc_ressize = sizeof(struct nfsd_voidres),
0335         .pc_cachetype = RC_NOCACHE,
0336         .pc_xdrressize = ST,
0337         .pc_name = "NULL",
0338     },
0339     [ACLPROC2_GETACL] = {
0340         .pc_func = nfsacld_proc_getacl,
0341         .pc_decode = nfsaclsvc_decode_getaclargs,
0342         .pc_encode = nfsaclsvc_encode_getaclres,
0343         .pc_release = nfsaclsvc_release_getacl,
0344         .pc_argsize = sizeof(struct nfsd3_getaclargs),
0345         .pc_ressize = sizeof(struct nfsd3_getaclres),
0346         .pc_cachetype = RC_NOCACHE,
0347         .pc_xdrressize = ST+1+2*(1+ACL),
0348         .pc_name = "GETACL",
0349     },
0350     [ACLPROC2_SETACL] = {
0351         .pc_func = nfsacld_proc_setacl,
0352         .pc_decode = nfsaclsvc_decode_setaclargs,
0353         .pc_encode = nfssvc_encode_attrstatres,
0354         .pc_release = nfssvc_release_attrstat,
0355         .pc_argsize = sizeof(struct nfsd3_setaclargs),
0356         .pc_ressize = sizeof(struct nfsd_attrstat),
0357         .pc_cachetype = RC_NOCACHE,
0358         .pc_xdrressize = ST+AT,
0359         .pc_name = "SETACL",
0360     },
0361     [ACLPROC2_GETATTR] = {
0362         .pc_func = nfsacld_proc_getattr,
0363         .pc_decode = nfssvc_decode_fhandleargs,
0364         .pc_encode = nfssvc_encode_attrstatres,
0365         .pc_release = nfssvc_release_attrstat,
0366         .pc_argsize = sizeof(struct nfsd_fhandle),
0367         .pc_ressize = sizeof(struct nfsd_attrstat),
0368         .pc_cachetype = RC_NOCACHE,
0369         .pc_xdrressize = ST+AT,
0370         .pc_name = "GETATTR",
0371     },
0372     [ACLPROC2_ACCESS] = {
0373         .pc_func = nfsacld_proc_access,
0374         .pc_decode = nfsaclsvc_decode_accessargs,
0375         .pc_encode = nfsaclsvc_encode_accessres,
0376         .pc_release = nfsaclsvc_release_access,
0377         .pc_argsize = sizeof(struct nfsd3_accessargs),
0378         .pc_ressize = sizeof(struct nfsd3_accessres),
0379         .pc_cachetype = RC_NOCACHE,
0380         .pc_xdrressize = ST+AT+1,
0381         .pc_name = "SETATTR",
0382     },
0383 };
0384 
0385 static unsigned int nfsd_acl_count2[ARRAY_SIZE(nfsd_acl_procedures2)];
0386 const struct svc_version nfsd_acl_version2 = {
0387     .vs_vers    = 2,
0388     .vs_nproc   = 5,
0389     .vs_proc    = nfsd_acl_procedures2,
0390     .vs_count   = nfsd_acl_count2,
0391     .vs_dispatch    = nfsd_dispatch,
0392     .vs_xdrsize = NFS3_SVC_XDRSIZE,
0393 };