aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
authorWeston Andros Adamson <dros@netapp.com>2013-09-03 15:18:49 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2013-09-03 15:25:10 -0400
commita5250def7c4549a6a1cd8257900bef9c12ffc2fc (patch)
tree99de00dbe175fc2a04eaf61530c342abb3921a39 /fs/nfs
parent35fa5f7b35ca2076d594b2670a32d66dd3ae9eec (diff)
NFSv4: use the mach cred for SECINFO w/ integrity
Commit 5ec16a8500d339b0e7a0cc76b785d18daad354d4 introduced a regression that causes SECINFO to fail without actualy sending an RPC if: 1) the nfs_client's rpc_client was using KRB5i/p (now tried by default) 2) the current user doesn't have valid kerberos credentials This situation is quite common - as of now a sec=sys mount would use krb5i for the nfs_client's rpc_client and a user would hardly be faulted for not having run kinit. The solution is to use the machine cred when trying to use an integrity protected auth flavor for SECINFO. Older servers may not support using the machine cred or an integrity protected auth flavor for SECINFO in every circumstance, so we fall back to using the user's cred and the filesystem's auth flavor in this case. We run into another problem when running against linux nfs servers - they return NFS4ERR_WRONGSEC when using integrity auth flavor (unless the mount is also that flavor) even though that is not a valid error for SECINFO*. Even though it's against spec, handle WRONGSEC errors on SECINFO by falling back to using the user cred and the filesystem's auth flavor. Signed-off-by: Weston Andros Adamson <dros@netapp.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs')
-rw-r--r--fs/nfs/nfs4proc.c53
1 files changed, 47 insertions, 6 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 09c7e3b87c46..85b190643e30 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -435,6 +435,20 @@ wait_on_recovery:
435 return ret; 435 return ret;
436} 436}
437 437
438/*
439 * Return 'true' if 'clp' is using an rpc_client that is integrity protected
440 * or 'false' otherwise.
441 */
442static bool _nfs4_is_integrity_protected(struct nfs_client *clp)
443{
444 rpc_authflavor_t flavor = clp->cl_rpcclient->cl_auth->au_flavor;
445
446 if (flavor == RPC_AUTH_GSS_KRB5I ||
447 flavor == RPC_AUTH_GSS_KRB5P)
448 return true;
449
450 return false;
451}
438 452
439static void do_renew_lease(struct nfs_client *clp, unsigned long timestamp) 453static void do_renew_lease(struct nfs_client *clp, unsigned long timestamp)
440{ 454{
@@ -5842,10 +5856,13 @@ int nfs4_proc_fs_locations(struct rpc_clnt *client, struct inode *dir,
5842} 5856}
5843 5857
5844/** 5858/**
5845 * Use the state managment nfs_client cl_rpcclient, which uses krb5i (if 5859 * If 'use_integrity' is true and the state managment nfs_client
5846 * possible) as per RFC3530bis and RFC5661 Security Considerations sections 5860 * cl_rpcclient is using krb5i/p, use the integrity protected cl_rpcclient
5861 * and the machine credential as per RFC3530bis and RFC5661 Security
5862 * Considerations sections. Otherwise, just use the user cred with the
5863 * filesystem's rpc_client.
5847 */ 5864 */
5848static int _nfs4_proc_secinfo(struct inode *dir, const struct qstr *name, struct nfs4_secinfo_flavors *flavors) 5865static int _nfs4_proc_secinfo(struct inode *dir, const struct qstr *name, struct nfs4_secinfo_flavors *flavors, bool use_integrity)
5849{ 5866{
5850 int status; 5867 int status;
5851 struct nfs4_secinfo_arg args = { 5868 struct nfs4_secinfo_arg args = {
@@ -5860,11 +5877,21 @@ static int _nfs4_proc_secinfo(struct inode *dir, const struct qstr *name, struct
5860 .rpc_argp = &args, 5877 .rpc_argp = &args,
5861 .rpc_resp = &res, 5878 .rpc_resp = &res,
5862 }; 5879 };
5863 struct rpc_clnt *clnt = NFS_SERVER(dir)->nfs_client->cl_rpcclient; 5880 struct rpc_clnt *clnt = NFS_SERVER(dir)->client;
5881
5882 if (use_integrity) {
5883 clnt = NFS_SERVER(dir)->nfs_client->cl_rpcclient;
5884 msg.rpc_cred = nfs4_get_clid_cred(NFS_SERVER(dir)->nfs_client);
5885 }
5864 5886
5865 dprintk("NFS call secinfo %s\n", name->name); 5887 dprintk("NFS call secinfo %s\n", name->name);
5866 status = nfs4_call_sync(clnt, NFS_SERVER(dir), &msg, &args.seq_args, &res.seq_res, 0); 5888 status = nfs4_call_sync(clnt, NFS_SERVER(dir), &msg, &args.seq_args,
5889 &res.seq_res, 0);
5867 dprintk("NFS reply secinfo: %d\n", status); 5890 dprintk("NFS reply secinfo: %d\n", status);
5891
5892 if (msg.rpc_cred)
5893 put_rpccred(msg.rpc_cred);
5894
5868 return status; 5895 return status;
5869} 5896}
5870 5897
@@ -5874,7 +5901,21 @@ int nfs4_proc_secinfo(struct inode *dir, const struct qstr *name,
5874 struct nfs4_exception exception = { }; 5901 struct nfs4_exception exception = { };
5875 int err; 5902 int err;
5876 do { 5903 do {
5877 err = _nfs4_proc_secinfo(dir, name, flavors); 5904 err = -NFS4ERR_WRONGSEC;
5905
5906 /* try to use integrity protection with machine cred */
5907 if (_nfs4_is_integrity_protected(NFS_SERVER(dir)->nfs_client))
5908 err = _nfs4_proc_secinfo(dir, name, flavors, true);
5909
5910 /*
5911 * if unable to use integrity protection, or SECINFO with
5912 * integrity protection returns NFS4ERR_WRONGSEC (which is
5913 * disallowed by spec, but exists in deployed servers) use
5914 * the current filesystem's rpc_client and the user cred.
5915 */
5916 if (err == -NFS4ERR_WRONGSEC)
5917 err = _nfs4_proc_secinfo(dir, name, flavors, false);
5918
5878 trace_nfs4_secinfo(dir, name, err); 5919 trace_nfs4_secinfo(dir, name, err);
5879 err = nfs4_handle_exception(NFS_SERVER(dir), err, 5920 err = nfs4_handle_exception(NFS_SERVER(dir), err,
5880 &exception); 5921 &exception);