Commit fca78d6d authored by Bryan Schumaker's avatar Bryan Schumaker Committed by Trond Myklebust

NFS: Add SECINFO_NO_NAME procedure

If the client is using NFS v4.1, then we can use SECINFO_NO_NAME to find
the secflavor for the initial mount.  If the server doesn't support
SECINFO_NO_NAME then I fall back on the "guess and check" method used
for v4.0 mounts.
Signed-off-by: default avatarBryan Schumaker <bjschuma@netapp.com>
Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent 6382a441
...@@ -277,6 +277,9 @@ extern void nfs_sb_deactive(struct super_block *sb); ...@@ -277,6 +277,9 @@ extern void nfs_sb_deactive(struct super_block *sb);
extern char *nfs_path(char **p, struct dentry *dentry, extern char *nfs_path(char **p, struct dentry *dentry,
char *buffer, ssize_t buflen); char *buffer, ssize_t buflen);
extern struct vfsmount *nfs_d_automount(struct path *path); extern struct vfsmount *nfs_d_automount(struct path *path);
#ifdef CONFIG_NFS_V4
rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *);
#endif
/* getroot.c */ /* getroot.c */
extern struct dentry *nfs_get_root(struct super_block *, struct nfs_fh *, extern struct dentry *nfs_get_root(struct super_block *, struct nfs_fh *,
......
...@@ -119,7 +119,7 @@ char *nfs_path(char **p, struct dentry *dentry, char *buffer, ssize_t buflen) ...@@ -119,7 +119,7 @@ char *nfs_path(char **p, struct dentry *dentry, char *buffer, ssize_t buflen)
} }
#ifdef CONFIG_NFS_V4 #ifdef CONFIG_NFS_V4
static rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *flavors) rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *flavors)
{ {
struct gss_api_mech *mech; struct gss_api_mech *mech;
struct xdr_netobj oid; struct xdr_netobj oid;
......
...@@ -67,6 +67,8 @@ struct nfs4_minor_version_ops { ...@@ -67,6 +67,8 @@ struct nfs4_minor_version_ops {
int cache_reply); int cache_reply);
int (*validate_stateid)(struct nfs_delegation *, int (*validate_stateid)(struct nfs_delegation *,
const nfs4_stateid *); const nfs4_stateid *);
int (*find_root_sec)(struct nfs_server *, struct nfs_fh *,
struct nfs_fsinfo *);
const struct nfs4_state_recovery_ops *reboot_recovery_ops; const struct nfs4_state_recovery_ops *reboot_recovery_ops;
const struct nfs4_state_recovery_ops *nograce_recovery_ops; const struct nfs4_state_recovery_ops *nograce_recovery_ops;
const struct nfs4_state_maintenance_ops *state_renewal_ops; const struct nfs4_state_maintenance_ops *state_renewal_ops;
......
...@@ -2251,13 +2251,14 @@ static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -2251,13 +2251,14 @@ static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
struct nfs_fsinfo *info) struct nfs_fsinfo *info)
{ {
int minor_version = server->nfs_client->cl_minorversion;
int status = nfs4_lookup_root(server, fhandle, info); int status = nfs4_lookup_root(server, fhandle, info);
if ((status == -NFS4ERR_WRONGSEC) && !(server->flags & NFS_MOUNT_SECFLAVOUR)) if ((status == -NFS4ERR_WRONGSEC) && !(server->flags & NFS_MOUNT_SECFLAVOUR))
/* /*
* A status of -NFS4ERR_WRONGSEC will be mapped to -EPERM * A status of -NFS4ERR_WRONGSEC will be mapped to -EPERM
* by nfs4_map_errors() as this function exits. * by nfs4_map_errors() as this function exits.
*/ */
status = nfs4_find_root_sec(server, fhandle, info); status = nfs_v4_minor_ops[minor_version]->find_root_sec(server, fhandle, info);
if (status == 0) if (status == 0)
status = nfs4_server_capabilities(server, fhandle); status = nfs4_server_capabilities(server, fhandle);
if (status == 0) if (status == 0)
...@@ -5935,6 +5936,85 @@ nfs4_proc_layoutcommit(struct nfs4_layoutcommit_data *data, bool sync) ...@@ -5935,6 +5936,85 @@ nfs4_proc_layoutcommit(struct nfs4_layoutcommit_data *data, bool sync)
rpc_put_task(task); rpc_put_task(task);
return status; return status;
} }
static int
_nfs41_proc_secinfo_no_name(struct nfs_server *server, struct nfs_fh *fhandle,
struct nfs_fsinfo *info, struct nfs4_secinfo_flavors *flavors)
{
struct nfs41_secinfo_no_name_args args = {
.style = SECINFO_STYLE_CURRENT_FH,
};
struct nfs4_secinfo_res res = {
.flavors = flavors,
};
struct rpc_message msg = {
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SECINFO_NO_NAME],
.rpc_argp = &args,
.rpc_resp = &res,
};
return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
}
static int
nfs41_proc_secinfo_no_name(struct nfs_server *server, struct nfs_fh *fhandle,
struct nfs_fsinfo *info, struct nfs4_secinfo_flavors *flavors)
{
struct nfs4_exception exception = { };
int err;
do {
err = _nfs41_proc_secinfo_no_name(server, fhandle, info, flavors);
switch (err) {
case 0:
case -NFS4ERR_WRONGSEC:
case -NFS4ERR_NOTSUPP:
break;
default:
err = nfs4_handle_exception(server, err, &exception);
}
} while (exception.retry);
return err;
}
static int
nfs41_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
struct nfs_fsinfo *info)
{
int err;
struct page *page;
rpc_authflavor_t flavor;
struct nfs4_secinfo_flavors *flavors;
page = alloc_page(GFP_KERNEL);
if (!page) {
err = -ENOMEM;
goto out;
}
flavors = page_address(page);
err = nfs41_proc_secinfo_no_name(server, fhandle, info, flavors);
/*
* Fall back on "guess and check" method if
* the server doesn't support SECINFO_NO_NAME
*/
if (err == -NFS4ERR_WRONGSEC || err == -NFS4ERR_NOTSUPP) {
err = nfs4_find_root_sec(server, fhandle, info);
goto out_freepage;
}
if (err)
goto out_freepage;
flavor = nfs_find_best_sec(flavors);
if (err == 0)
err = nfs4_lookup_root_sec(server, fhandle, info, flavor);
out_freepage:
put_page(page);
if (err == -EACCES)
return -EPERM;
out:
return err;
}
#endif /* CONFIG_NFS_V4_1 */ #endif /* CONFIG_NFS_V4_1 */
struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = { struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = {
...@@ -5996,6 +6076,7 @@ static const struct nfs4_minor_version_ops nfs_v4_0_minor_ops = { ...@@ -5996,6 +6076,7 @@ static const struct nfs4_minor_version_ops nfs_v4_0_minor_ops = {
.minor_version = 0, .minor_version = 0,
.call_sync = _nfs4_call_sync, .call_sync = _nfs4_call_sync,
.validate_stateid = nfs4_validate_delegation_stateid, .validate_stateid = nfs4_validate_delegation_stateid,
.find_root_sec = nfs4_find_root_sec,
.reboot_recovery_ops = &nfs40_reboot_recovery_ops, .reboot_recovery_ops = &nfs40_reboot_recovery_ops,
.nograce_recovery_ops = &nfs40_nograce_recovery_ops, .nograce_recovery_ops = &nfs40_nograce_recovery_ops,
.state_renewal_ops = &nfs40_state_renewal_ops, .state_renewal_ops = &nfs40_state_renewal_ops,
...@@ -6006,6 +6087,7 @@ static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = { ...@@ -6006,6 +6087,7 @@ static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = {
.minor_version = 1, .minor_version = 1,
.call_sync = _nfs4_call_sync_session, .call_sync = _nfs4_call_sync_session,
.validate_stateid = nfs41_validate_delegation_stateid, .validate_stateid = nfs41_validate_delegation_stateid,
.find_root_sec = nfs41_find_root_sec,
.reboot_recovery_ops = &nfs41_reboot_recovery_ops, .reboot_recovery_ops = &nfs41_reboot_recovery_ops,
.nograce_recovery_ops = &nfs41_nograce_recovery_ops, .nograce_recovery_ops = &nfs41_nograce_recovery_ops,
.state_renewal_ops = &nfs41_state_renewal_ops, .state_renewal_ops = &nfs41_state_renewal_ops,
......
...@@ -343,6 +343,8 @@ static int nfs4_stat_to_errno(int); ...@@ -343,6 +343,8 @@ static int nfs4_stat_to_errno(int);
1 /* FIXME: opaque lrf_body always empty at the moment */) 1 /* FIXME: opaque lrf_body always empty at the moment */)
#define decode_layoutreturn_maxsz (op_decode_hdr_maxsz + \ #define decode_layoutreturn_maxsz (op_decode_hdr_maxsz + \
1 + decode_stateid_maxsz) 1 + decode_stateid_maxsz)
#define encode_secinfo_no_name_maxsz (op_encode_hdr_maxsz + 1)
#define decode_secinfo_no_name_maxsz decode_secinfo_maxsz
#else /* CONFIG_NFS_V4_1 */ #else /* CONFIG_NFS_V4_1 */
#define encode_sequence_maxsz 0 #define encode_sequence_maxsz 0
#define decode_sequence_maxsz 0 #define decode_sequence_maxsz 0
...@@ -772,6 +774,14 @@ static int nfs4_stat_to_errno(int); ...@@ -772,6 +774,14 @@ static int nfs4_stat_to_errno(int);
decode_sequence_maxsz + \ decode_sequence_maxsz + \
decode_putfh_maxsz + \ decode_putfh_maxsz + \
decode_layoutreturn_maxsz) decode_layoutreturn_maxsz)
#define NFS4_enc_secinfo_no_name_sz (compound_encode_hdr_maxsz + \
encode_sequence_maxsz + \
encode_putrootfh_maxsz +\
encode_secinfo_no_name_maxsz)
#define NFS4_dec_secinfo_no_name_sz (compound_decode_hdr_maxsz + \
decode_sequence_maxsz + \
decode_putrootfh_maxsz + \
decode_secinfo_no_name_maxsz)
const u32 nfs41_maxwrite_overhead = ((RPC_MAX_HEADER_WITH_AUTH + const u32 nfs41_maxwrite_overhead = ((RPC_MAX_HEADER_WITH_AUTH +
compound_encode_hdr_maxsz + compound_encode_hdr_maxsz +
...@@ -1938,6 +1948,20 @@ encode_layoutreturn(struct xdr_stream *xdr, ...@@ -1938,6 +1948,20 @@ encode_layoutreturn(struct xdr_stream *xdr,
hdr->nops++; hdr->nops++;
hdr->replen += decode_layoutreturn_maxsz; hdr->replen += decode_layoutreturn_maxsz;
} }
static int
encode_secinfo_no_name(struct xdr_stream *xdr,
const struct nfs41_secinfo_no_name_args *args,
struct compound_hdr *hdr)
{
__be32 *p;
p = reserve_space(xdr, 8);
*p++ = cpu_to_be32(OP_SECINFO_NO_NAME);
*p++ = cpu_to_be32(args->style);
hdr->nops++;
hdr->replen += decode_secinfo_no_name_maxsz;
return 0;
}
#endif /* CONFIG_NFS_V4_1 */ #endif /* CONFIG_NFS_V4_1 */
/* /*
...@@ -2790,6 +2814,25 @@ static void nfs4_xdr_enc_layoutreturn(struct rpc_rqst *req, ...@@ -2790,6 +2814,25 @@ static void nfs4_xdr_enc_layoutreturn(struct rpc_rqst *req,
encode_layoutreturn(xdr, args, &hdr); encode_layoutreturn(xdr, args, &hdr);
encode_nops(&hdr); encode_nops(&hdr);
} }
/*
* Encode SECINFO_NO_NAME request
*/
static int nfs4_xdr_enc_secinfo_no_name(struct rpc_rqst *req,
struct xdr_stream *xdr,
struct nfs41_secinfo_no_name_args *args)
{
struct compound_hdr hdr = {
.minorversion = nfs4_xdr_minorversion(&args->seq_args),
};
encode_compound_hdr(xdr, req, &hdr);
encode_sequence(xdr, &args->seq_args, &hdr);
encode_putrootfh(xdr, &hdr);
encode_secinfo_no_name(xdr, args, &hdr);
encode_nops(&hdr);
return 0;
}
#endif /* CONFIG_NFS_V4_1 */ #endif /* CONFIG_NFS_V4_1 */
static void print_overflow_msg(const char *func, const struct xdr_stream *xdr) static void print_overflow_msg(const char *func, const struct xdr_stream *xdr)
...@@ -6467,6 +6510,30 @@ static int nfs4_xdr_dec_layoutcommit(struct rpc_rqst *rqstp, ...@@ -6467,6 +6510,30 @@ static int nfs4_xdr_dec_layoutcommit(struct rpc_rqst *rqstp,
out: out:
return status; return status;
} }
/*
* Decode SECINFO_NO_NAME response
*/
static int nfs4_xdr_dec_secinfo_no_name(struct rpc_rqst *rqstp,
struct xdr_stream *xdr,
struct nfs4_secinfo_res *res)
{
struct compound_hdr hdr;
int status;
status = decode_compound_hdr(xdr, &hdr);
if (status)
goto out;
status = decode_sequence(xdr, &res->seq_res, rqstp);
if (status)
goto out;
status = decode_putrootfh(xdr);
if (status)
goto out;
status = decode_secinfo(xdr, res);
out:
return status;
}
#endif /* CONFIG_NFS_V4_1 */ #endif /* CONFIG_NFS_V4_1 */
/** /**
...@@ -6669,6 +6736,7 @@ struct rpc_procinfo nfs4_procedures[] = { ...@@ -6669,6 +6736,7 @@ struct rpc_procinfo nfs4_procedures[] = {
PROC(LAYOUTGET, enc_layoutget, dec_layoutget), PROC(LAYOUTGET, enc_layoutget, dec_layoutget),
PROC(LAYOUTCOMMIT, enc_layoutcommit, dec_layoutcommit), PROC(LAYOUTCOMMIT, enc_layoutcommit, dec_layoutcommit),
PROC(LAYOUTRETURN, enc_layoutreturn, dec_layoutreturn), PROC(LAYOUTRETURN, enc_layoutreturn, dec_layoutreturn),
PROC(SECINFO_NO_NAME, enc_secinfo_no_name, dec_secinfo_no_name),
#endif /* CONFIG_NFS_V4_1 */ #endif /* CONFIG_NFS_V4_1 */
}; };
......
...@@ -563,6 +563,7 @@ enum { ...@@ -563,6 +563,7 @@ enum {
NFSPROC4_CLNT_GETDEVICEINFO, NFSPROC4_CLNT_GETDEVICEINFO,
NFSPROC4_CLNT_LAYOUTCOMMIT, NFSPROC4_CLNT_LAYOUTCOMMIT,
NFSPROC4_CLNT_LAYOUTRETURN, NFSPROC4_CLNT_LAYOUTRETURN,
NFSPROC4_CLNT_SECINFO_NO_NAME,
}; };
/* nfs41 types */ /* nfs41 types */
......
...@@ -1084,6 +1084,14 @@ struct nfs41_reclaim_complete_args { ...@@ -1084,6 +1084,14 @@ struct nfs41_reclaim_complete_args {
struct nfs41_reclaim_complete_res { struct nfs41_reclaim_complete_res {
struct nfs4_sequence_res seq_res; struct nfs4_sequence_res seq_res;
}; };
#define SECINFO_STYLE_CURRENT_FH 0
#define SECINFO_STYLE_PARENT 1
struct nfs41_secinfo_no_name_args {
int style;
struct nfs4_sequence_args seq_args;
};
#endif /* CONFIG_NFS_V4_1 */ #endif /* CONFIG_NFS_V4_1 */
struct nfs_page; struct nfs_page;
......
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