NFS: Use root's credential for lease management when keytab is missing
authorChuck Lever <chuck.lever@oracle.com>
Wed, 24 Jul 2013 16:28:28 +0000 (12:28 -0400)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Wed, 7 Aug 2013 17:05:10 +0000 (13:05 -0400)
Commit 05f4c350 "NFS: Discover NFSv4 server trunking when mounting"
Fri Sep 14 17:24:32 2012 introduced Uniform Client String support,
which forces our NFS client to establish a client ID immediately
during a mount operation rather than waiting until a user wants to
open a file.

Normally machine credentials (eg. from a keytab) are used to perform
a mount operation that is protected by Kerberos.  Before 05fc350,
SETCLIENTID used a machine credential, or fell back to a regular
user's credential if no keytab is available.

On clients that don't have a keytab, performing SETCLIENTID early
means there's no user credential to fall back on, since no regular
user has kinit'd yet.  05f4c350 seems to have broken the ability
to mount with sec=krb5 on clients that don't have a keytab in
kernels 3.7 - 3.10.

To address this regression, commit 4edaa308 (NFS: Use "krb5i" to
establish NFSv4 state whenever possible), Sat Mar 16 15:56:20 2013,
was merged in 3.10.  This commit forces the NFS client to fall back
to AUTH_SYS for lease management operations if no keytab is
available.

Neil Brown noticed that, since root is required to kinit to do a
sec=krb5 mount when a client doesn't have a keytab, we can try to
use root's Kerberos credential before AUTH_SYS.

Now, when determining a principal and flavor to use for lease
management, the NFS client tries in this order:

  1.  Flavor: AUTH_GSS, krb5i
      Principal: service principal (via keytab)

  2.  Flavor: AUTH_GSS, krb5i
      Principal: user principal established for UID 0 (via kinit)

  3.  Flavor: AUTH_SYS
      Principal: UID 0 / GID 0

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
fs/nfs/nfs4state.c

index ad1a753..f27760b 100644 (file)
@@ -154,6 +154,19 @@ struct rpc_cred *nfs4_get_machine_cred_locked(struct nfs_client *clp)
        return cred;
 }
 
+static void nfs4_root_machine_cred(struct nfs_client *clp)
+{
+       struct rpc_cred *cred, *new;
+
+       new = rpc_lookup_machine_cred(NULL);
+       spin_lock(&clp->cl_lock);
+       cred = clp->cl_machine_cred;
+       clp->cl_machine_cred = new;
+       spin_unlock(&clp->cl_lock);
+       if (cred != NULL)
+               put_rpccred(cred);
+}
+
 static struct rpc_cred *
 nfs4_get_renew_cred_server_locked(struct nfs_server *server)
 {
@@ -1896,7 +1909,11 @@ again:
                        __func__, status);
                goto again;
        case -EACCES:
-               if (i++)
+               if (i++ == 0) {
+                       nfs4_root_machine_cred(clp);
+                       goto again;
+               }
+               if (i > 2)
                        break;
        case -NFS4ERR_CLID_INUSE:
        case -NFS4ERR_WRONGSEC: