Commit cb25e7b2 authored by Chuck Lever's avatar Chuck Lever Committed by J. Bruce Fields

nfsd: Use correct credential for NFSv4.0 callback with GSS

I've had trouble when operating a multi-homed Linux NFS server with
Kerberos using NFSv4.0. Lately, I've seen my clients reporting
this (and then hanging):

May  9 11:43:26 manet kernel: NFS: NFSv4 callback contains invalid cred

The client-side commit f11b2a1c ("nfs4: copy acceptor name from
context to nfs_client") appears to be related, but I suspect this
problem has been going on for some time before that.

RFC 7530 Section 3.3.3 says:
> For Kerberos V5, nfs/hostname would be a server principal in the
> Kerberos Key Distribution Center database.  This is the same
> principal the client acquired a GSS-API context for when it issued
> the SETCLIENTID operation ...

In other words, an NFSv4.0 client expects that the server will use
the same GSS principal for callback that the client used to
establish its lease. For example, if the client used the service
principal "nfs@server.domain" to establish its lease, the server
is required to use "nfs@server.domain" when performing NFSv4.0
callback operations.

The Linux NFS server currently does not. It uses a common service
principal for all callback connections. Sometimes this works as
expected, and other times -- for example, when the server is
accessible via multiple hostnames -- it won't work at all.

This patch scrapes the target name from the client credential,
and uses that for the NFSv4.0 callback credential. That should
be correct much more often.
Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
Signed-off-by: default avatarJ. Bruce Fields <bfields@redhat.com>
parent 9abdda5d
...@@ -769,7 +769,14 @@ void cleanup_callback_cred(void) ...@@ -769,7 +769,14 @@ void cleanup_callback_cred(void)
static struct rpc_cred *get_backchannel_cred(struct nfs4_client *clp, struct rpc_clnt *client, struct nfsd4_session *ses) static struct rpc_cred *get_backchannel_cred(struct nfs4_client *clp, struct rpc_clnt *client, struct nfsd4_session *ses)
{ {
if (clp->cl_minorversion == 0) { if (clp->cl_minorversion == 0) {
return get_rpccred(callback_cred); char *principal = clp->cl_cred.cr_targ_princ ?
clp->cl_cred.cr_targ_princ : "nfs";
struct rpc_cred *cred;
cred = rpc_lookup_machine_cred(principal);
if (!IS_ERR(cred))
get_rpccred(cred);
return cred;
} else { } else {
struct rpc_auth *auth = client->cl_auth; struct rpc_auth *auth = client->cl_auth;
struct auth_cred acred = {}; struct auth_cred acred = {};
......
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