mirror of
https://github.com/torvalds/linux.git
synced 2024-12-27 21:33:00 +00:00
NFSD: add posix ACLs to struct nfsd_attrs
pacl and dpacl pointers are added to struct nfsd_attrs, which requires that we have an nfsd_attrs_free() function to free them. Those nfsv4 functions that can set ACLs now set up these pointers based on the passed in NFSv4 ACL. nfsd_setattr() sets the acls as appropriate. Errors are handled as with security labels. Signed-off-by: NeilBrown <neilb@suse.de> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
This commit is contained in:
parent
d6a97d3f58
commit
c0cbe70742
@ -38,6 +38,8 @@
|
|||||||
struct nfs4_acl;
|
struct nfs4_acl;
|
||||||
struct svc_fh;
|
struct svc_fh;
|
||||||
struct svc_rqst;
|
struct svc_rqst;
|
||||||
|
struct nfsd_attrs;
|
||||||
|
enum nfs_ftype4;
|
||||||
|
|
||||||
int nfs4_acl_bytes(int entries);
|
int nfs4_acl_bytes(int entries);
|
||||||
int nfs4_acl_get_whotype(char *, u32);
|
int nfs4_acl_get_whotype(char *, u32);
|
||||||
@ -45,7 +47,7 @@ __be32 nfs4_acl_write_who(struct xdr_stream *xdr, int who);
|
|||||||
|
|
||||||
int nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry,
|
int nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry,
|
||||||
struct nfs4_acl **acl);
|
struct nfs4_acl **acl);
|
||||||
__be32 nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
__be32 nfsd4_acl_to_attr(enum nfs_ftype4 type, struct nfs4_acl *acl,
|
||||||
struct nfs4_acl *acl);
|
struct nfsd_attrs *attr);
|
||||||
|
|
||||||
#endif /* LINUX_NFS4_ACL_H */
|
#endif /* LINUX_NFS4_ACL_H */
|
||||||
|
@ -751,58 +751,26 @@ out_estate:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
__be32
|
__be32 nfsd4_acl_to_attr(enum nfs_ftype4 type, struct nfs4_acl *acl,
|
||||||
nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
struct nfsd_attrs *attr)
|
||||||
struct nfs4_acl *acl)
|
|
||||||
{
|
{
|
||||||
__be32 error;
|
|
||||||
int host_error;
|
int host_error;
|
||||||
struct dentry *dentry;
|
|
||||||
struct inode *inode;
|
|
||||||
struct posix_acl *pacl = NULL, *dpacl = NULL;
|
|
||||||
unsigned int flags = 0;
|
unsigned int flags = 0;
|
||||||
|
|
||||||
/* Get inode */
|
if (!acl)
|
||||||
error = fh_verify(rqstp, fhp, 0, NFSD_MAY_SATTR);
|
return nfs_ok;
|
||||||
if (error)
|
|
||||||
return error;
|
|
||||||
|
|
||||||
dentry = fhp->fh_dentry;
|
if (type == NF4DIR)
|
||||||
inode = d_inode(dentry);
|
|
||||||
|
|
||||||
if (S_ISDIR(inode->i_mode))
|
|
||||||
flags = NFS4_ACL_DIR;
|
flags = NFS4_ACL_DIR;
|
||||||
|
|
||||||
host_error = nfs4_acl_nfsv4_to_posix(acl, &pacl, &dpacl, flags);
|
host_error = nfs4_acl_nfsv4_to_posix(acl, &attr->na_pacl,
|
||||||
|
&attr->na_dpacl, flags);
|
||||||
if (host_error == -EINVAL)
|
if (host_error == -EINVAL)
|
||||||
return nfserr_attrnotsupp;
|
return nfserr_attrnotsupp;
|
||||||
if (host_error < 0)
|
|
||||||
goto out_nfserr;
|
|
||||||
|
|
||||||
fh_lock(fhp);
|
|
||||||
|
|
||||||
host_error = set_posix_acl(&init_user_ns, inode, ACL_TYPE_ACCESS, pacl);
|
|
||||||
if (host_error < 0)
|
|
||||||
goto out_drop_lock;
|
|
||||||
|
|
||||||
if (S_ISDIR(inode->i_mode)) {
|
|
||||||
host_error = set_posix_acl(&init_user_ns, inode,
|
|
||||||
ACL_TYPE_DEFAULT, dpacl);
|
|
||||||
}
|
|
||||||
|
|
||||||
out_drop_lock:
|
|
||||||
fh_unlock(fhp);
|
|
||||||
|
|
||||||
posix_acl_release(pacl);
|
|
||||||
posix_acl_release(dpacl);
|
|
||||||
out_nfserr:
|
|
||||||
if (host_error == -EOPNOTSUPP)
|
|
||||||
return nfserr_attrnotsupp;
|
|
||||||
else
|
else
|
||||||
return nfserrno(host_error);
|
return nfserrno(host_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static short
|
static short
|
||||||
ace2type(struct nfs4_ace *ace)
|
ace2type(struct nfs4_ace *ace)
|
||||||
{
|
{
|
||||||
|
@ -128,26 +128,6 @@ is_create_with_attrs(struct nfsd4_open *open)
|
|||||||
|| open->op_createmode == NFS4_CREATE_EXCLUSIVE4_1);
|
|| open->op_createmode == NFS4_CREATE_EXCLUSIVE4_1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* if error occurs when setting the acl, just clear the acl bit
|
|
||||||
* in the returned attr bitmap.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
do_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
|
||||||
struct nfs4_acl *acl, u32 *bmval)
|
|
||||||
{
|
|
||||||
__be32 status;
|
|
||||||
|
|
||||||
status = nfsd4_set_nfs4_acl(rqstp, fhp, acl);
|
|
||||||
if (status)
|
|
||||||
/*
|
|
||||||
* We should probably fail the whole open at this point,
|
|
||||||
* but we've already created the file, so it's too late;
|
|
||||||
* So this seems the least of evils:
|
|
||||||
*/
|
|
||||||
bmval[0] &= ~FATTR4_WORD0_ACL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
fh_dup2(struct svc_fh *dst, struct svc_fh *src)
|
fh_dup2(struct svc_fh *dst, struct svc_fh *src)
|
||||||
{
|
{
|
||||||
@ -281,6 +261,9 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
|||||||
if (host_err)
|
if (host_err)
|
||||||
return nfserrno(host_err);
|
return nfserrno(host_err);
|
||||||
|
|
||||||
|
if (is_create_with_attrs(open))
|
||||||
|
nfsd4_acl_to_attr(NF4REG, open->op_acl, &attrs);
|
||||||
|
|
||||||
fh_lock_nested(fhp, I_MUTEX_PARENT);
|
fh_lock_nested(fhp, I_MUTEX_PARENT);
|
||||||
|
|
||||||
child = lookup_one_len(open->op_fname, parent, open->op_fnamelen);
|
child = lookup_one_len(open->op_fname, parent, open->op_fnamelen);
|
||||||
@ -382,8 +365,11 @@ set_attr:
|
|||||||
|
|
||||||
if (attrs.na_labelerr)
|
if (attrs.na_labelerr)
|
||||||
open->op_bmval[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
|
open->op_bmval[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
|
||||||
|
if (attrs.na_aclerr)
|
||||||
|
open->op_bmval[0] &= ~FATTR4_WORD0_ACL;
|
||||||
out:
|
out:
|
||||||
fh_unlock(fhp);
|
fh_unlock(fhp);
|
||||||
|
nfsd_attrs_free(&attrs);
|
||||||
if (child && !IS_ERR(child))
|
if (child && !IS_ERR(child))
|
||||||
dput(child);
|
dput(child);
|
||||||
fh_drop_write(fhp);
|
fh_drop_write(fhp);
|
||||||
@ -446,9 +432,6 @@ do_open_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, stru
|
|||||||
if (status)
|
if (status)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (is_create_with_attrs(open) && open->op_acl != NULL)
|
|
||||||
do_set_nfs4_acl(rqstp, *resfh, open->op_acl, open->op_bmval);
|
|
||||||
|
|
||||||
nfsd4_set_open_owner_reply_cache(cstate, open, *resfh);
|
nfsd4_set_open_owner_reply_cache(cstate, open, *resfh);
|
||||||
accmode = NFSD_MAY_NOP;
|
accmode = NFSD_MAY_NOP;
|
||||||
if (open->op_created ||
|
if (open->op_created ||
|
||||||
@ -779,6 +762,7 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
|||||||
if (status)
|
if (status)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
|
status = nfsd4_acl_to_attr(create->cr_type, create->cr_acl, &attrs);
|
||||||
current->fs->umask = create->cr_umask;
|
current->fs->umask = create->cr_umask;
|
||||||
switch (create->cr_type) {
|
switch (create->cr_type) {
|
||||||
case NF4LNK:
|
case NF4LNK:
|
||||||
@ -837,10 +821,8 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
|||||||
|
|
||||||
if (attrs.na_labelerr)
|
if (attrs.na_labelerr)
|
||||||
create->cr_bmval[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
|
create->cr_bmval[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
|
||||||
|
if (attrs.na_aclerr)
|
||||||
if (create->cr_acl != NULL)
|
create->cr_bmval[0] &= ~FATTR4_WORD0_ACL;
|
||||||
do_set_nfs4_acl(rqstp, &resfh, create->cr_acl,
|
|
||||||
create->cr_bmval);
|
|
||||||
|
|
||||||
fh_unlock(&cstate->current_fh);
|
fh_unlock(&cstate->current_fh);
|
||||||
set_change_info(&create->cr_cinfo, &cstate->current_fh);
|
set_change_info(&create->cr_cinfo, &cstate->current_fh);
|
||||||
@ -849,6 +831,7 @@ out:
|
|||||||
fh_put(&resfh);
|
fh_put(&resfh);
|
||||||
out_umask:
|
out_umask:
|
||||||
current->fs->umask = 0;
|
current->fs->umask = 0;
|
||||||
|
nfsd_attrs_free(&attrs);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1123,6 +1106,7 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
|||||||
.na_iattr = &setattr->sa_iattr,
|
.na_iattr = &setattr->sa_iattr,
|
||||||
.na_seclabel = &setattr->sa_label,
|
.na_seclabel = &setattr->sa_label,
|
||||||
};
|
};
|
||||||
|
struct inode *inode;
|
||||||
__be32 status = nfs_ok;
|
__be32 status = nfs_ok;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
@ -1145,9 +1129,10 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
|||||||
if (status)
|
if (status)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (setattr->sa_acl != NULL)
|
inode = cstate->current_fh.fh_dentry->d_inode;
|
||||||
status = nfsd4_set_nfs4_acl(rqstp, &cstate->current_fh,
|
status = nfsd4_acl_to_attr(S_ISDIR(inode->i_mode) ? NF4DIR : NF4REG,
|
||||||
setattr->sa_acl);
|
setattr->sa_acl, &attrs);
|
||||||
|
|
||||||
if (status)
|
if (status)
|
||||||
goto out;
|
goto out;
|
||||||
status = nfsd_setattr(rqstp, &cstate->current_fh, &attrs,
|
status = nfsd_setattr(rqstp, &cstate->current_fh, &attrs,
|
||||||
@ -1155,6 +1140,7 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
|||||||
if (!status)
|
if (!status)
|
||||||
status = nfserrno(attrs.na_labelerr);
|
status = nfserrno(attrs.na_labelerr);
|
||||||
out:
|
out:
|
||||||
|
nfsd_attrs_free(&attrs);
|
||||||
fh_drop_write(&cstate->current_fh);
|
fh_drop_write(&cstate->current_fh);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
@ -461,6 +461,15 @@ out_unlock:
|
|||||||
if (attr->na_seclabel && attr->na_seclabel->len)
|
if (attr->na_seclabel && attr->na_seclabel->len)
|
||||||
attr->na_labelerr = security_inode_setsecctx(dentry,
|
attr->na_labelerr = security_inode_setsecctx(dentry,
|
||||||
attr->na_seclabel->data, attr->na_seclabel->len);
|
attr->na_seclabel->data, attr->na_seclabel->len);
|
||||||
|
if (IS_ENABLED(CONFIG_FS_POSIX_ACL) && attr->na_pacl)
|
||||||
|
attr->na_aclerr = set_posix_acl(&init_user_ns,
|
||||||
|
inode, ACL_TYPE_ACCESS,
|
||||||
|
attr->na_pacl);
|
||||||
|
if (IS_ENABLED(CONFIG_FS_POSIX_ACL) &&
|
||||||
|
!attr->na_aclerr && attr->na_dpacl && S_ISDIR(inode->i_mode))
|
||||||
|
attr->na_aclerr = set_posix_acl(&init_user_ns,
|
||||||
|
inode, ACL_TYPE_DEFAULT,
|
||||||
|
attr->na_dpacl);
|
||||||
fh_unlock(fhp);
|
fh_unlock(fhp);
|
||||||
if (size_change)
|
if (size_change)
|
||||||
put_write_access(inode);
|
put_write_access(inode);
|
||||||
|
@ -6,6 +6,8 @@
|
|||||||
#ifndef LINUX_NFSD_VFS_H
|
#ifndef LINUX_NFSD_VFS_H
|
||||||
#define LINUX_NFSD_VFS_H
|
#define LINUX_NFSD_VFS_H
|
||||||
|
|
||||||
|
#include <linux/fs.h>
|
||||||
|
#include <linux/posix_acl.h>
|
||||||
#include "nfsfh.h"
|
#include "nfsfh.h"
|
||||||
#include "nfsd.h"
|
#include "nfsd.h"
|
||||||
|
|
||||||
@ -45,10 +47,19 @@ typedef int (*nfsd_filldir_t)(void *, const char *, int, loff_t, u64, unsigned);
|
|||||||
struct nfsd_attrs {
|
struct nfsd_attrs {
|
||||||
struct iattr *na_iattr; /* input */
|
struct iattr *na_iattr; /* input */
|
||||||
struct xdr_netobj *na_seclabel; /* input */
|
struct xdr_netobj *na_seclabel; /* input */
|
||||||
|
struct posix_acl *na_pacl; /* input */
|
||||||
|
struct posix_acl *na_dpacl; /* input */
|
||||||
|
|
||||||
int na_labelerr; /* output */
|
int na_labelerr; /* output */
|
||||||
|
int na_aclerr; /* output */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static inline void nfsd_attrs_free(struct nfsd_attrs *attrs)
|
||||||
|
{
|
||||||
|
posix_acl_release(attrs->na_pacl);
|
||||||
|
posix_acl_release(attrs->na_dpacl);
|
||||||
|
}
|
||||||
|
|
||||||
int nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp,
|
int nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp,
|
||||||
struct svc_export **expp);
|
struct svc_export **expp);
|
||||||
__be32 nfsd_lookup(struct svc_rqst *, struct svc_fh *,
|
__be32 nfsd_lookup(struct svc_rqst *, struct svc_fh *,
|
||||||
|
Loading…
Reference in New Issue
Block a user