Commit a1108921 authored by Trond Myklebust's avatar Trond Myklebust

NFSv2/v3: Ensure that we only use GETATTR+STATFS (NFSv2) and FSINFO (NFSv3) when

     mounting. This should allow us to use AUTH_SYS credentials when mounting,
     (even when the user requests RPCSEC_GSS authentication) due to the hack
     described in RFC2623.

     Remove the broken NFS_INO_FAKE_ROOT hack.
parent bacab44f
......@@ -231,50 +231,23 @@ nfs_block_size(unsigned long bsize, unsigned char *nrbitsp)
/*
* Obtain the root inode of the file system.
*/
static int
nfs_get_root(struct inode **rooti, rpc_authflavor_t authflavor, struct super_block *sb, struct nfs_fh *rootfh)
static struct inode *
nfs_get_root(struct super_block *sb, struct nfs_fh *rootfh, struct nfs_fsinfo *fsinfo)
{
struct nfs_server *server = NFS_SB(sb);
struct nfs_fattr fattr = { };
struct inode *rooti;
int error;
error = server->rpc_ops->getroot(server, rootfh, &fattr);
if (error == -EACCES && authflavor > RPC_AUTH_MAXFLAVOR) {
/*
* Some authentication types (gss/krb5, most notably)
* are such that root won't be able to present a
* credential for GETATTR (ie, getroot()).
*
* We still want the mount to succeed.
*
* So we fake the attr values and mark the inode as such.
* On the first succesful traversal, we fix everything.
* The auth type test isn't quite correct, but whatever.
*/
dfprintk(VFS, "NFS: faking root inode\n");
fattr.fileid = 1;
fattr.nlink = 2; /* minimum for a dir */
fattr.type = NFDIR;
fattr.mode = S_IFDIR|S_IRUGO|S_IXUGO;
fattr.size = 4096;
fattr.du.nfs3.used = 1;
fattr.valid = NFS_ATTR_FATTR|NFS_ATTR_FATTR_V3;
} else if (error < 0) {
error = server->rpc_ops->getroot(server, rootfh, fsinfo);
if (error < 0) {
printk(KERN_NOTICE "nfs_get_root: getattr error = %d\n", -error);
*rooti = NULL; /* superfluous ... but safe */
return error;
return ERR_PTR(error);
}
*rooti = nfs_fhget(sb, rootfh, &fattr);
if (error == -EACCES && authflavor > RPC_AUTH_MAXFLAVOR) {
if (*rooti) {
NFS_FLAGS(*rooti) |= NFS_INO_FAKE_ROOT;
NFS_CACHEINV((*rooti));
error = 0;
}
}
return error;
rooti = nfs_fhget(sb, rootfh, fsinfo->fattr);
if (!rooti)
return ERR_PTR(-ENOMEM);
return rooti;
}
/*
......@@ -284,7 +257,7 @@ static int
nfs_sb_init(struct super_block *sb, rpc_authflavor_t authflavor)
{
struct nfs_server *server;
struct inode *root_inode = NULL;
struct inode *root_inode;
struct nfs_fattr fattr;
struct nfs_fsinfo fsinfo = {
.fattr = &fattr,
......@@ -300,8 +273,9 @@ nfs_sb_init(struct super_block *sb, rpc_authflavor_t authflavor)
sb->s_magic = NFS_SUPER_MAGIC;
root_inode = nfs_get_root(sb, &server->fh, &fsinfo);
/* Did getting the root inode fail? */
if (nfs_get_root(&root_inode, authflavor, sb, &server->fh) < 0)
if (IS_ERR(root_inode))
goto out_no_root;
sb->s_root = d_alloc_root(root_inode);
if (!sb->s_root)
......@@ -310,10 +284,6 @@ nfs_sb_init(struct super_block *sb, rpc_authflavor_t authflavor)
sb->s_root->d_op = server->rpc_ops->dentry_ops;
/* Get some general file system info */
if (server->rpc_ops->fsinfo(server, &server->fh, &fsinfo) < 0) {
printk(KERN_NOTICE "NFS: cannot retrieve file system info.\n");
goto out_no_root;
}
if (server->namelen == 0 &&
server->rpc_ops->pathconf(server, &server->fh, &pathinfo) >= 0)
server->namelen = pathinfo.max_namelen;
......@@ -369,13 +339,11 @@ nfs_sb_init(struct super_block *sb, rpc_authflavor_t authflavor)
rpc_setbufsize(server->client, server->wsize + 100, server->rsize + 100);
return 0;
/* Yargs. It didn't work out. */
out_free_all:
if (root_inode)
iput(root_inode);
return -EINVAL;
out_no_root:
printk("nfs_read_super: get root inode failed\n");
goto out_free_all;
if (!IS_ERR(root_inode))
iput(root_inode);
return -EINVAL;
}
/*
......@@ -1160,13 +1128,6 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsign
if ((fattr->valid & NFS_ATTR_FATTR) == 0)
return 0;
/* First successful call after mount, fill real data. */
if (NFS_FAKE_ROOT(inode)) {
dfprintk(VFS, "NFS: updating fake root\n");
nfsi->fileid = fattr->fileid;
NFS_FLAGS(inode) &= ~NFS_INO_FAKE_ROOT;
}
if (nfsi->fileid != fattr->fileid) {
printk(KERN_ERR "%s: inode number mismatch\n"
"expected (%s/0x%Lx), got (%s/0x%Lx)\n",
......
......@@ -85,14 +85,18 @@ nfs_cred(struct inode *inode, struct file *filp)
*/
static int
nfs3_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
struct nfs_fattr *fattr)
struct nfs_fsinfo *info)
{
int status;
dprintk("NFS call getroot\n");
fattr->valid = 0;
status = rpc_call(server->client, NFS3PROC_GETATTR, fhandle, fattr, 0);
dprintk("NFS reply getroot\n");
dprintk("%s: call fsinfo\n", __FUNCTION__);
info->fattr->valid = 0;
status = rpc_call(server->client_sys, NFS3PROC_FSINFO, fhandle, info, 0);
dprintk("%s: reply fsinfo %d\n", __FUNCTION__, status);
if (!(info->fattr->valid & NFS_ATTR_FATTR)) {
status = rpc_call(server->client_sys, NFS3PROC_GETATTR, fhandle, info->fattr, 0);
dprintk("%s: reply getattr %d\n", __FUNCTION__, status);
}
return status;
}
......
......@@ -54,6 +54,7 @@
#define GET_OP(cp,name) &cp->ops[cp->req_nops].u.name
#define OPNUM(cp) cp->ops[cp->req_nops].opnum
static int nfs4_proc_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *);
static int nfs4_async_handle_error(struct rpc_task *, struct nfs_server *);
extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus);
extern struct rpc_procinfo nfs4_procedures[];
......@@ -822,10 +823,11 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags)
static int
nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
struct nfs_fattr *fattr)
struct nfs_fsinfo *info)
{
struct nfs4_compound compound;
struct nfs4_op ops[4];
struct nfs_fattr * fattr = info->fattr;
unsigned char * p;
struct qstr q;
int status;
......@@ -869,7 +871,9 @@ nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
break;
}
out:
if (status)
return status;
return nfs4_proc_fsinfo(server, fhandle, info);
}
static int
......@@ -1458,7 +1462,6 @@ nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
struct nfs4_compound compound;
struct nfs4_op ops[2];
memset(fsstat, 0, sizeof(*fsstat));
nfs4_setup_compound(&compound, ops, server, "statfs");
nfs4_setup_putfh(&compound, fhandle);
nfs4_setup_statfs(&compound, fsstat);
......@@ -1475,7 +1478,6 @@ nfs4_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle,
.rpc_resp = fsinfo,
};
memset(fsinfo, 0, sizeof(*fsinfo));
return rpc_call_sync(server->client, &msg, 0);
}
......@@ -1486,7 +1488,6 @@ nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
struct nfs4_compound compound;
struct nfs4_op ops[2];
memset(pathconf, 0, sizeof(*pathconf));
nfs4_setup_compound(&compound, ops, server, "statfs");
nfs4_setup_putfh(&compound, fhandle);
nfs4_setup_pathconf(&compound, pathconf);
......
......@@ -66,15 +66,33 @@ nfs_cred(struct inode *inode, struct file *filp)
*/
static int
nfs_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
struct nfs_fattr *fattr)
struct nfs_fsinfo *info)
{
struct nfs_fattr *fattr = info->fattr;
struct nfs2_fsstat fsinfo;
int status;
dprintk("NFS call getroot\n");
dprintk("%s: call getattr\n", __FUNCTION__);
fattr->valid = 0;
status = rpc_call(server->client, NFSPROC_GETATTR, fhandle, fattr, 0);
dprintk("NFS reply getroot\n");
status = rpc_call(server->client_sys, NFSPROC_GETATTR, fhandle, fattr, 0);
dprintk("%s: reply getattr %d\n", __FUNCTION__, status);
if (status)
return status;
dprintk("%s: call statfs\n", __FUNCTION__);
status = rpc_call(server->client_sys, NFSPROC_STATFS, fhandle, &fsinfo, 0);
dprintk("%s: reply statfs %d\n", __FUNCTION__, status);
if (status)
return status;
info->rtmax = NFS_MAXDATA;
info->rtpref = fsinfo.tsize;
info->rtmult = fsinfo.bsize;
info->wtmax = NFS_MAXDATA;
info->wtpref = fsinfo.tsize;
info->wtmult = fsinfo.bsize;
info->dtpref = fsinfo.tsize;
info->maxfilesize = 0x7FFFFFFF;
info->lease_time = 0;
return 0;
}
/*
......
......@@ -176,7 +176,6 @@ struct nfs_inode {
#define NFS_INO_INVALID_ATTR 0x0008 /* cached attrs are invalid */
#define NFS_INO_INVALID_DATA 0x0010 /* cached data is invalid */
#define NFS_INO_INVALID_ATIME 0x0020 /* cached atime is invalid */
#define NFS_INO_FAKE_ROOT 0x0080 /* root inode placeholder */
static inline struct nfs_inode *NFS_I(struct inode *inode)
{
......@@ -204,7 +203,6 @@ static inline struct nfs_inode *NFS_I(struct inode *inode)
#define NFS_FLAGS(inode) (NFS_I(inode)->flags)
#define NFS_REVALIDATING(inode) (NFS_FLAGS(inode) & NFS_INO_REVALIDATING)
#define NFS_STALE(inode) (NFS_FLAGS(inode) & NFS_INO_STALE)
#define NFS_FAKE_ROOT(inode) (NFS_FLAGS(inode) & NFS_INO_FAKE_ROOT)
#define NFS_FILEID(inode) (NFS_I(inode)->fileid)
......
......@@ -700,7 +700,7 @@ struct nfs_rpc_ops {
struct inode_operations *dir_inode_ops;
int (*getroot) (struct nfs_server *, struct nfs_fh *,
struct nfs_fattr *);
struct nfs_fsinfo *);
int (*getattr) (struct inode *, struct nfs_fattr *);
int (*setattr) (struct dentry *, struct nfs_fattr *,
struct iattr *);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment