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) ...@@ -231,50 +231,23 @@ nfs_block_size(unsigned long bsize, unsigned char *nrbitsp)
/* /*
* Obtain the root inode of the file system. * Obtain the root inode of the file system.
*/ */
static int static struct inode *
nfs_get_root(struct inode **rooti, rpc_authflavor_t authflavor, struct super_block *sb, struct nfs_fh *rootfh) nfs_get_root(struct super_block *sb, struct nfs_fh *rootfh, struct nfs_fsinfo *fsinfo)
{ {
struct nfs_server *server = NFS_SB(sb); struct nfs_server *server = NFS_SB(sb);
struct nfs_fattr fattr = { }; struct inode *rooti;
int error; int error;
error = server->rpc_ops->getroot(server, rootfh, &fattr); error = server->rpc_ops->getroot(server, rootfh, fsinfo);
if (error == -EACCES && authflavor > RPC_AUTH_MAXFLAVOR) { if (error < 0) {
/*
* 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) {
printk(KERN_NOTICE "nfs_get_root: getattr error = %d\n", -error); printk(KERN_NOTICE "nfs_get_root: getattr error = %d\n", -error);
*rooti = NULL; /* superfluous ... but safe */ return ERR_PTR(error);
return error;
} }
*rooti = nfs_fhget(sb, rootfh, &fattr); rooti = nfs_fhget(sb, rootfh, fsinfo->fattr);
if (error == -EACCES && authflavor > RPC_AUTH_MAXFLAVOR) { if (!rooti)
if (*rooti) { return ERR_PTR(-ENOMEM);
NFS_FLAGS(*rooti) |= NFS_INO_FAKE_ROOT; return rooti;
NFS_CACHEINV((*rooti));
error = 0;
}
}
return error;
} }
/* /*
...@@ -284,7 +257,7 @@ static int ...@@ -284,7 +257,7 @@ static int
nfs_sb_init(struct super_block *sb, rpc_authflavor_t authflavor) nfs_sb_init(struct super_block *sb, rpc_authflavor_t authflavor)
{ {
struct nfs_server *server; struct nfs_server *server;
struct inode *root_inode = NULL; struct inode *root_inode;
struct nfs_fattr fattr; struct nfs_fattr fattr;
struct nfs_fsinfo fsinfo = { struct nfs_fsinfo fsinfo = {
.fattr = &fattr, .fattr = &fattr,
...@@ -300,8 +273,9 @@ nfs_sb_init(struct super_block *sb, rpc_authflavor_t authflavor) ...@@ -300,8 +273,9 @@ nfs_sb_init(struct super_block *sb, rpc_authflavor_t authflavor)
sb->s_magic = NFS_SUPER_MAGIC; sb->s_magic = NFS_SUPER_MAGIC;
root_inode = nfs_get_root(sb, &server->fh, &fsinfo);
/* Did getting the root inode fail? */ /* 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; goto out_no_root;
sb->s_root = d_alloc_root(root_inode); sb->s_root = d_alloc_root(root_inode);
if (!sb->s_root) if (!sb->s_root)
...@@ -310,10 +284,6 @@ nfs_sb_init(struct super_block *sb, rpc_authflavor_t authflavor) ...@@ -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; sb->s_root->d_op = server->rpc_ops->dentry_ops;
/* Get some general file system info */ /* 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 && if (server->namelen == 0 &&
server->rpc_ops->pathconf(server, &server->fh, &pathinfo) >= 0) server->rpc_ops->pathconf(server, &server->fh, &pathinfo) >= 0)
server->namelen = pathinfo.max_namelen; server->namelen = pathinfo.max_namelen;
...@@ -369,13 +339,11 @@ nfs_sb_init(struct super_block *sb, rpc_authflavor_t authflavor) ...@@ -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); rpc_setbufsize(server->client, server->wsize + 100, server->rsize + 100);
return 0; return 0;
/* Yargs. It didn't work out. */ /* Yargs. It didn't work out. */
out_free_all:
if (root_inode)
iput(root_inode);
return -EINVAL;
out_no_root: out_no_root:
printk("nfs_read_super: get root inode failed\n"); 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 ...@@ -1160,13 +1128,6 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsign
if ((fattr->valid & NFS_ATTR_FATTR) == 0) if ((fattr->valid & NFS_ATTR_FATTR) == 0)
return 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) { if (nfsi->fileid != fattr->fileid) {
printk(KERN_ERR "%s: inode number mismatch\n" printk(KERN_ERR "%s: inode number mismatch\n"
"expected (%s/0x%Lx), got (%s/0x%Lx)\n", "expected (%s/0x%Lx), got (%s/0x%Lx)\n",
......
...@@ -85,14 +85,18 @@ nfs_cred(struct inode *inode, struct file *filp) ...@@ -85,14 +85,18 @@ nfs_cred(struct inode *inode, struct file *filp)
*/ */
static int static int
nfs3_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, nfs3_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
struct nfs_fattr *fattr) struct nfs_fsinfo *info)
{ {
int status; int status;
dprintk("NFS call getroot\n"); dprintk("%s: call fsinfo\n", __FUNCTION__);
fattr->valid = 0; info->fattr->valid = 0;
status = rpc_call(server->client, NFS3PROC_GETATTR, fhandle, fattr, 0); status = rpc_call(server->client_sys, NFS3PROC_FSINFO, fhandle, info, 0);
dprintk("NFS reply getroot\n"); 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; return status;
} }
......
...@@ -54,6 +54,7 @@ ...@@ -54,6 +54,7 @@
#define GET_OP(cp,name) &cp->ops[cp->req_nops].u.name #define GET_OP(cp,name) &cp->ops[cp->req_nops].u.name
#define OPNUM(cp) cp->ops[cp->req_nops].opnum #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 *); 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 u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus);
extern struct rpc_procinfo nfs4_procedures[]; extern struct rpc_procinfo nfs4_procedures[];
...@@ -822,10 +823,11 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags) ...@@ -822,10 +823,11 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags)
static int static int
nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, 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_compound compound;
struct nfs4_op ops[4]; struct nfs4_op ops[4];
struct nfs_fattr * fattr = info->fattr;
unsigned char * p; unsigned char * p;
struct qstr q; struct qstr q;
int status; int status;
...@@ -869,7 +871,9 @@ nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -869,7 +871,9 @@ nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
break; break;
} }
out: out:
return status; if (status)
return status;
return nfs4_proc_fsinfo(server, fhandle, info);
} }
static int static int
...@@ -1458,7 +1462,6 @@ nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -1458,7 +1462,6 @@ nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
struct nfs4_compound compound; struct nfs4_compound compound;
struct nfs4_op ops[2]; struct nfs4_op ops[2];
memset(fsstat, 0, sizeof(*fsstat));
nfs4_setup_compound(&compound, ops, server, "statfs"); nfs4_setup_compound(&compound, ops, server, "statfs");
nfs4_setup_putfh(&compound, fhandle); nfs4_setup_putfh(&compound, fhandle);
nfs4_setup_statfs(&compound, fsstat); nfs4_setup_statfs(&compound, fsstat);
...@@ -1475,7 +1478,6 @@ nfs4_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -1475,7 +1478,6 @@ nfs4_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle,
.rpc_resp = fsinfo, .rpc_resp = fsinfo,
}; };
memset(fsinfo, 0, sizeof(*fsinfo));
return rpc_call_sync(server->client, &msg, 0); return rpc_call_sync(server->client, &msg, 0);
} }
...@@ -1486,7 +1488,6 @@ nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -1486,7 +1488,6 @@ nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
struct nfs4_compound compound; struct nfs4_compound compound;
struct nfs4_op ops[2]; struct nfs4_op ops[2];
memset(pathconf, 0, sizeof(*pathconf));
nfs4_setup_compound(&compound, ops, server, "statfs"); nfs4_setup_compound(&compound, ops, server, "statfs");
nfs4_setup_putfh(&compound, fhandle); nfs4_setup_putfh(&compound, fhandle);
nfs4_setup_pathconf(&compound, pathconf); nfs4_setup_pathconf(&compound, pathconf);
......
...@@ -66,15 +66,33 @@ nfs_cred(struct inode *inode, struct file *filp) ...@@ -66,15 +66,33 @@ nfs_cred(struct inode *inode, struct file *filp)
*/ */
static int static int
nfs_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, nfs_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
struct nfs_fattr *fattr) struct nfs_fsinfo *info)
{ {
int status; 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; fattr->valid = 0;
status = rpc_call(server->client, NFSPROC_GETATTR, fhandle, fattr, 0); status = rpc_call(server->client_sys, NFSPROC_GETATTR, fhandle, fattr, 0);
dprintk("NFS reply getroot\n"); dprintk("%s: reply getattr %d\n", __FUNCTION__, status);
return 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 { ...@@ -176,7 +176,6 @@ struct nfs_inode {
#define NFS_INO_INVALID_ATTR 0x0008 /* cached attrs are invalid */ #define NFS_INO_INVALID_ATTR 0x0008 /* cached attrs are invalid */
#define NFS_INO_INVALID_DATA 0x0010 /* cached data is invalid */ #define NFS_INO_INVALID_DATA 0x0010 /* cached data is invalid */
#define NFS_INO_INVALID_ATIME 0x0020 /* cached atime 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) static inline struct nfs_inode *NFS_I(struct inode *inode)
{ {
...@@ -204,7 +203,6 @@ 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_FLAGS(inode) (NFS_I(inode)->flags)
#define NFS_REVALIDATING(inode) (NFS_FLAGS(inode) & NFS_INO_REVALIDATING) #define NFS_REVALIDATING(inode) (NFS_FLAGS(inode) & NFS_INO_REVALIDATING)
#define NFS_STALE(inode) (NFS_FLAGS(inode) & NFS_INO_STALE) #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) #define NFS_FILEID(inode) (NFS_I(inode)->fileid)
......
...@@ -700,7 +700,7 @@ struct nfs_rpc_ops { ...@@ -700,7 +700,7 @@ struct nfs_rpc_ops {
struct inode_operations *dir_inode_ops; struct inode_operations *dir_inode_ops;
int (*getroot) (struct nfs_server *, struct nfs_fh *, int (*getroot) (struct nfs_server *, struct nfs_fh *,
struct nfs_fattr *); struct nfs_fsinfo *);
int (*getattr) (struct inode *, struct nfs_fattr *); int (*getattr) (struct inode *, struct nfs_fattr *);
int (*setattr) (struct dentry *, struct nfs_fattr *, int (*setattr) (struct dentry *, struct nfs_fattr *,
struct iattr *); 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