aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2013-04-23 15:40:40 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2013-04-23 15:40:40 -0400
commitbd1d421abcaae1b84ba377ea4c33bba31d654199 (patch)
tree10bf67d7063a95ffd013a9d01a35b906a7d89fcf /fs
parentbdeca1b76cd56cd10a029f0ad2fd9ab6dd7e313d (diff)
parent79d852bf5e7691dc78cc6322ecd1860c50940785 (diff)
Merge branch 'rpcsec_gss-from_cel' into linux-next
* rpcsec_gss-from_cel: (21 commits) NFS: Retry SETCLIENTID with AUTH_SYS instead of AUTH_NONE NFSv4: Don't clear the machine cred when client establish returns EACCES NFSv4: Fix issues in nfs4_discover_server_trunking NFSv4: Fix the fallback to AUTH_NULL if krb5i is not available NFS: Use server-recommended security flavor by default (NFSv3) SUNRPC: Don't recognize RPC_AUTH_MAXFLAVOR NFS: Use "krb5i" to establish NFSv4 state whenever possible NFS: Try AUTH_UNIX when PUTROOTFH gets NFS4ERR_WRONGSEC NFS: Use static list of security flavors during root FH lookup recovery NFS: Avoid PUTROOTFH when managing leases NFS: Clean up nfs4_proc_get_rootfh NFS: Handle missing rpc.gssd when looking up root FH SUNRPC: Remove EXPORT_SYMBOL_GPL() from GSS mech switch SUNRPC: Make gss_mech_get() static SUNRPC: Refactor nfsd4_do_encode_secinfo() SUNRPC: Consider qop when looking up pseudoflavors SUNRPC: Load GSS kernel module by OID SUNRPC: Introduce rpcauth_get_pseudoflavor() SUNRPC: Define rpcsec_gss_info structure NFS: Remove unneeded forward declaration ...
Diffstat (limited to 'fs')
-rw-r--r--fs/nfs/nfs4client.c4
-rw-r--r--fs/nfs/nfs4namespace.c43
-rw-r--r--fs/nfs/nfs4proc.c92
-rw-r--r--fs/nfs/nfs4state.c60
-rw-r--r--fs/nfs/nfs4super.c2
-rw-r--r--fs/nfs/nfs4xdr.c39
-rw-r--r--fs/nfs/super.c80
-rw-r--r--fs/nfsd/nfs4xdr.c24
8 files changed, 164 insertions, 180 deletions
diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c
index f4d4d4ec6bf7..c2b069e25819 100644
--- a/fs/nfs/nfs4client.c
+++ b/fs/nfs/nfs4client.c
@@ -201,7 +201,9 @@ struct nfs_client *nfs4_init_client(struct nfs_client *clp,
201 if (clp->cl_minorversion != 0) 201 if (clp->cl_minorversion != 0)
202 __set_bit(NFS_CS_INFINITE_SLOTS, &clp->cl_flags); 202 __set_bit(NFS_CS_INFINITE_SLOTS, &clp->cl_flags);
203 __set_bit(NFS_CS_DISCRTRY, &clp->cl_flags); 203 __set_bit(NFS_CS_DISCRTRY, &clp->cl_flags);
204 error = nfs_create_rpc_client(clp, timeparms, authflavour); 204 error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_GSS_KRB5I);
205 if (error == -EINVAL)
206 error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_NULL);
205 if (error < 0) 207 if (error < 0)
206 goto error; 208 goto error;
207 209
diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c
index 0dd766079e1c..cdb0b41a4810 100644
--- a/fs/nfs/nfs4namespace.c
+++ b/fs/nfs/nfs4namespace.c
@@ -134,33 +134,38 @@ static size_t nfs_parse_server_name(char *string, size_t len,
134 return ret; 134 return ret;
135} 135}
136 136
137/**
138 * nfs_find_best_sec - Find a security mechanism supported locally
139 * @flavors: List of security tuples returned by SECINFO procedure
140 *
141 * Return the pseudoflavor of the first security mechanism in
142 * "flavors" that is locally supported. Return RPC_AUTH_UNIX if
143 * no matching flavor is found in the array. The "flavors" array
144 * is searched in the order returned from the server, per RFC 3530
145 * recommendation.
146 */
137rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *flavors) 147rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *flavors)
138{ 148{
139 struct gss_api_mech *mech; 149 rpc_authflavor_t pseudoflavor;
140 struct xdr_netobj oid; 150 struct nfs4_secinfo4 *secinfo;
141 int i; 151 unsigned int i;
142 rpc_authflavor_t pseudoflavor = RPC_AUTH_UNIX;
143 152
144 for (i = 0; i < flavors->num_flavors; i++) { 153 for (i = 0; i < flavors->num_flavors; i++) {
145 struct nfs4_secinfo_flavor *flavor; 154 secinfo = &flavors->flavors[i];
146 flavor = &flavors->flavors[i]; 155
147 156 switch (secinfo->flavor) {
148 if (flavor->flavor == RPC_AUTH_NULL || flavor->flavor == RPC_AUTH_UNIX) { 157 case RPC_AUTH_NULL:
149 pseudoflavor = flavor->flavor; 158 case RPC_AUTH_UNIX:
150 break; 159 case RPC_AUTH_GSS:
151 } else if (flavor->flavor == RPC_AUTH_GSS) { 160 pseudoflavor = rpcauth_get_pseudoflavor(secinfo->flavor,
152 oid.len = flavor->gss.sec_oid4.len; 161 &secinfo->flavor_info);
153 oid.data = flavor->gss.sec_oid4.data; 162 if (pseudoflavor != RPC_AUTH_MAXFLAVOR)
154 mech = gss_mech_get_by_OID(&oid); 163 return pseudoflavor;
155 if (!mech)
156 continue;
157 pseudoflavor = gss_svc_to_pseudoflavor(mech, flavor->gss.service);
158 gss_mech_put(mech);
159 break; 164 break;
160 } 165 }
161 } 166 }
162 167
163 return pseudoflavor; 168 return RPC_AUTH_UNIX;
164} 169}
165 170
166static rpc_authflavor_t nfs4_negotiate_security(struct inode *inode, struct qstr *name) 171static rpc_authflavor_t nfs4_negotiate_security(struct inode *inode, struct qstr *name)
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index e18b3b46c001..e13b7ccee98d 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -2547,7 +2547,7 @@ static int nfs4_lookup_root_sec(struct nfs_server *server, struct nfs_fh *fhandl
2547 2547
2548 auth = rpcauth_create(flavor, server->client); 2548 auth = rpcauth_create(flavor, server->client);
2549 if (IS_ERR(auth)) { 2549 if (IS_ERR(auth)) {
2550 ret = -EIO; 2550 ret = -EACCES;
2551 goto out; 2551 goto out;
2552 } 2552 }
2553 ret = nfs4_lookup_root(server, fhandle, info); 2553 ret = nfs4_lookup_root(server, fhandle, info);
@@ -2555,27 +2555,36 @@ out:
2555 return ret; 2555 return ret;
2556} 2556}
2557 2557
2558/*
2559 * Retry pseudoroot lookup with various security flavors. We do this when:
2560 *
2561 * NFSv4.0: the PUTROOTFH operation returns NFS4ERR_WRONGSEC
2562 * NFSv4.1: the server does not support the SECINFO_NO_NAME operation
2563 *
2564 * Returns zero on success, or a negative NFS4ERR value, or a
2565 * negative errno value.
2566 */
2558static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle, 2567static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
2559 struct nfs_fsinfo *info) 2568 struct nfs_fsinfo *info)
2560{ 2569{
2561 int i, len, status = 0; 2570 /* Per 3530bis 15.33.5 */
2562 rpc_authflavor_t flav_array[NFS_MAX_SECFLAVORS]; 2571 static const rpc_authflavor_t flav_array[] = {
2563 2572 RPC_AUTH_GSS_KRB5P,
2564 len = rpcauth_list_flavors(flav_array, ARRAY_SIZE(flav_array)); 2573 RPC_AUTH_GSS_KRB5I,
2565 if (len < 0) 2574 RPC_AUTH_GSS_KRB5,
2566 return len; 2575 RPC_AUTH_UNIX, /* courtesy */
2567 2576 RPC_AUTH_NULL,
2568 for (i = 0; i < len; i++) { 2577 };
2569 /* AUTH_UNIX is the default flavor if none was specified, 2578 int status = -EPERM;
2570 * thus has already been tried. */ 2579 size_t i;
2571 if (flav_array[i] == RPC_AUTH_UNIX)
2572 continue;
2573 2580
2581 for (i = 0; i < ARRAY_SIZE(flav_array); i++) {
2574 status = nfs4_lookup_root_sec(server, fhandle, info, flav_array[i]); 2582 status = nfs4_lookup_root_sec(server, fhandle, info, flav_array[i]);
2575 if (status == -NFS4ERR_WRONGSEC || status == -EACCES) 2583 if (status == -NFS4ERR_WRONGSEC || status == -EACCES)
2576 continue; 2584 continue;
2577 break; 2585 break;
2578 } 2586 }
2587
2579 /* 2588 /*
2580 * -EACCESS could mean that the user doesn't have correct permissions 2589 * -EACCESS could mean that the user doesn't have correct permissions
2581 * to access the mount. It could also mean that we tried to mount 2590 * to access the mount. It could also mean that we tried to mount
@@ -2588,24 +2597,36 @@ static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
2588 return status; 2597 return status;
2589} 2598}
2590 2599
2591/* 2600static int nfs4_do_find_root_sec(struct nfs_server *server,
2592 * get the file handle for the "/" directory on the server 2601 struct nfs_fh *fhandle, struct nfs_fsinfo *info)
2602{
2603 int mv = server->nfs_client->cl_minorversion;
2604 return nfs_v4_minor_ops[mv]->find_root_sec(server, fhandle, info);
2605}
2606
2607/**
2608 * nfs4_proc_get_rootfh - get file handle for server's pseudoroot
2609 * @server: initialized nfs_server handle
2610 * @fhandle: we fill in the pseudo-fs root file handle
2611 * @info: we fill in an FSINFO struct
2612 *
2613 * Returns zero on success, or a negative errno.
2593 */ 2614 */
2594int nfs4_proc_get_rootfh(struct nfs_server *server, struct nfs_fh *fhandle, 2615int nfs4_proc_get_rootfh(struct nfs_server *server, struct nfs_fh *fhandle,
2595 struct nfs_fsinfo *info) 2616 struct nfs_fsinfo *info)
2596{ 2617{
2597 int minor_version = server->nfs_client->cl_minorversion; 2618 int status;
2598 int status = nfs4_lookup_root(server, fhandle, info); 2619
2599 if ((status == -NFS4ERR_WRONGSEC) && !(server->flags & NFS_MOUNT_SECFLAVOUR)) 2620 status = nfs4_lookup_root(server, fhandle, info);
2600 /* 2621 if ((status == -NFS4ERR_WRONGSEC) &&
2601 * A status of -NFS4ERR_WRONGSEC will be mapped to -EPERM 2622 !(server->flags & NFS_MOUNT_SECFLAVOUR))
2602 * by nfs4_map_errors() as this function exits. 2623 status = nfs4_do_find_root_sec(server, fhandle, info);
2603 */ 2624
2604 status = nfs_v4_minor_ops[minor_version]->find_root_sec(server, fhandle, info);
2605 if (status == 0) 2625 if (status == 0)
2606 status = nfs4_server_capabilities(server, fhandle); 2626 status = nfs4_server_capabilities(server, fhandle);
2607 if (status == 0) 2627 if (status == 0)
2608 status = nfs4_do_fsinfo(server, fhandle, info); 2628 status = nfs4_do_fsinfo(server, fhandle, info);
2629
2609 return nfs4_map_errors(status); 2630 return nfs4_map_errors(status);
2610} 2631}
2611 2632
@@ -3484,12 +3505,21 @@ static int _nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle,
3484static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo) 3505static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo)
3485{ 3506{
3486 struct nfs4_exception exception = { }; 3507 struct nfs4_exception exception = { };
3508 unsigned long now = jiffies;
3487 int err; 3509 int err;
3488 3510
3489 do { 3511 do {
3490 err = nfs4_handle_exception(server, 3512 err = _nfs4_do_fsinfo(server, fhandle, fsinfo);
3491 _nfs4_do_fsinfo(server, fhandle, fsinfo), 3513 if (err == 0) {
3492 &exception); 3514 struct nfs_client *clp = server->nfs_client;
3515
3516 spin_lock(&clp->cl_lock);
3517 clp->cl_lease_time = fsinfo->lease_time * HZ;
3518 clp->cl_last_renewal = now;
3519 spin_unlock(&clp->cl_lock);
3520 break;
3521 }
3522 err = nfs4_handle_exception(server, err, &exception);
3493 } while (exception.retry); 3523 } while (exception.retry);
3494 return err; 3524 return err;
3495} 3525}
@@ -4330,27 +4360,17 @@ int nfs4_proc_setclientid_confirm(struct nfs_client *clp,
4330 struct nfs4_setclientid_res *arg, 4360 struct nfs4_setclientid_res *arg,
4331 struct rpc_cred *cred) 4361 struct rpc_cred *cred)
4332{ 4362{
4333 struct nfs_fsinfo fsinfo;
4334 struct rpc_message msg = { 4363 struct rpc_message msg = {
4335 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETCLIENTID_CONFIRM], 4364 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETCLIENTID_CONFIRM],
4336 .rpc_argp = arg, 4365 .rpc_argp = arg,
4337 .rpc_resp = &fsinfo,
4338 .rpc_cred = cred, 4366 .rpc_cred = cred,
4339 }; 4367 };
4340 unsigned long now;
4341 int status; 4368 int status;
4342 4369
4343 dprintk("NFS call setclientid_confirm auth=%s, (client ID %llx)\n", 4370 dprintk("NFS call setclientid_confirm auth=%s, (client ID %llx)\n",
4344 clp->cl_rpcclient->cl_auth->au_ops->au_name, 4371 clp->cl_rpcclient->cl_auth->au_ops->au_name,
4345 clp->cl_clientid); 4372 clp->cl_clientid);
4346 now = jiffies;
4347 status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT); 4373 status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
4348 if (status == 0) {
4349 spin_lock(&clp->cl_lock);
4350 clp->cl_lease_time = fsinfo.lease_time * HZ;
4351 clp->cl_last_renewal = now;
4352 spin_unlock(&clp->cl_lock);
4353 }
4354 dprintk("NFS reply setclientid_confirm: %d\n", status); 4374 dprintk("NFS reply setclientid_confirm: %d\n", status);
4355 return status; 4375 return status;
4356} 4376}
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index b7796950eceb..7a74ea64bf54 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -154,18 +154,6 @@ struct rpc_cred *nfs4_get_machine_cred_locked(struct nfs_client *clp)
154 return cred; 154 return cred;
155} 155}
156 156
157static void nfs4_clear_machine_cred(struct nfs_client *clp)
158{
159 struct rpc_cred *cred;
160
161 spin_lock(&clp->cl_lock);
162 cred = clp->cl_machine_cred;
163 clp->cl_machine_cred = NULL;
164 spin_unlock(&clp->cl_lock);
165 if (cred != NULL)
166 put_rpccred(cred);
167}
168
169static struct rpc_cred * 157static struct rpc_cred *
170nfs4_get_renew_cred_server_locked(struct nfs_server *server) 158nfs4_get_renew_cred_server_locked(struct nfs_server *server)
171{ 159{
@@ -1776,10 +1764,6 @@ static int nfs4_handle_reclaim_lease_error(struct nfs_client *clp, int status)
1776 clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state); 1764 clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
1777 return -EPERM; 1765 return -EPERM;
1778 case -EACCES: 1766 case -EACCES:
1779 if (clp->cl_machine_cred == NULL)
1780 return -EACCES;
1781 /* Handle case where the user hasn't set up machine creds */
1782 nfs4_clear_machine_cred(clp);
1783 case -NFS4ERR_DELAY: 1767 case -NFS4ERR_DELAY:
1784 case -ETIMEDOUT: 1768 case -ETIMEDOUT:
1785 case -EAGAIN: 1769 case -EAGAIN:
@@ -1874,31 +1858,18 @@ int nfs4_discover_server_trunking(struct nfs_client *clp,
1874{ 1858{
1875 const struct nfs4_state_recovery_ops *ops = 1859 const struct nfs4_state_recovery_ops *ops =
1876 clp->cl_mvops->reboot_recovery_ops; 1860 clp->cl_mvops->reboot_recovery_ops;
1877 rpc_authflavor_t *flavors, flav, save;
1878 struct rpc_clnt *clnt; 1861 struct rpc_clnt *clnt;
1879 struct rpc_cred *cred; 1862 struct rpc_cred *cred;
1880 int i, len, status; 1863 int i, status;
1881 1864
1882 dprintk("NFS: %s: testing '%s'\n", __func__, clp->cl_hostname); 1865 dprintk("NFS: %s: testing '%s'\n", __func__, clp->cl_hostname);
1883 1866
1884 len = NFS_MAX_SECFLAVORS;
1885 flavors = kcalloc(len, sizeof(*flavors), GFP_KERNEL);
1886 if (flavors == NULL) {
1887 status = -ENOMEM;
1888 goto out;
1889 }
1890 len = rpcauth_list_flavors(flavors, len);
1891 if (len < 0) {
1892 status = len;
1893 goto out_free;
1894 }
1895 clnt = clp->cl_rpcclient; 1867 clnt = clp->cl_rpcclient;
1896 save = clnt->cl_auth->au_flavor;
1897 i = 0; 1868 i = 0;
1898 1869
1899 mutex_lock(&nfs_clid_init_mutex); 1870 mutex_lock(&nfs_clid_init_mutex);
1900 status = -ENOENT;
1901again: 1871again:
1872 status = -ENOENT;
1902 cred = ops->get_clid_cred(clp); 1873 cred = ops->get_clid_cred(clp);
1903 if (cred == NULL) 1874 if (cred == NULL)
1904 goto out_unlock; 1875 goto out_unlock;
@@ -1908,12 +1879,6 @@ again:
1908 switch (status) { 1879 switch (status) {
1909 case 0: 1880 case 0:
1910 break; 1881 break;
1911
1912 case -EACCES:
1913 if (clp->cl_machine_cred == NULL)
1914 break;
1915 /* Handle case where the user hasn't set up machine creds */
1916 nfs4_clear_machine_cred(clp);
1917 case -NFS4ERR_DELAY: 1882 case -NFS4ERR_DELAY:
1918 case -ETIMEDOUT: 1883 case -ETIMEDOUT:
1919 case -EAGAIN: 1884 case -EAGAIN:
@@ -1922,17 +1887,12 @@ again:
1922 dprintk("NFS: %s after status %d, retrying\n", 1887 dprintk("NFS: %s after status %d, retrying\n",
1923 __func__, status); 1888 __func__, status);
1924 goto again; 1889 goto again;
1925 1890 case -EACCES:
1891 if (i++)
1892 break;
1926 case -NFS4ERR_CLID_INUSE: 1893 case -NFS4ERR_CLID_INUSE:
1927 case -NFS4ERR_WRONGSEC: 1894 case -NFS4ERR_WRONGSEC:
1928 status = -EPERM; 1895 clnt = rpc_clone_client_set_auth(clnt, RPC_AUTH_UNIX);
1929 if (i >= len)
1930 break;
1931
1932 flav = flavors[i++];
1933 if (flav == save)
1934 flav = flavors[i++];
1935 clnt = rpc_clone_client_set_auth(clnt, flav);
1936 if (IS_ERR(clnt)) { 1896 if (IS_ERR(clnt)) {
1937 status = PTR_ERR(clnt); 1897 status = PTR_ERR(clnt);
1938 break; 1898 break;
@@ -1948,13 +1908,15 @@ again:
1948 case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery 1908 case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery
1949 * in nfs4_exchange_id */ 1909 * in nfs4_exchange_id */
1950 status = -EKEYEXPIRED; 1910 status = -EKEYEXPIRED;
1911 break;
1912 default:
1913 pr_warn("NFS: %s unhandled error %d. Exiting with error EIO\n",
1914 __func__, status);
1915 status = -EIO;
1951 } 1916 }
1952 1917
1953out_unlock: 1918out_unlock:
1954 mutex_unlock(&nfs_clid_init_mutex); 1919 mutex_unlock(&nfs_clid_init_mutex);
1955out_free:
1956 kfree(flavors);
1957out:
1958 dprintk("NFS: %s: status = %d\n", __func__, status); 1920 dprintk("NFS: %s: status = %d\n", __func__, status);
1959 return status; 1921 return status;
1960} 1922}
diff --git a/fs/nfs/nfs4super.c b/fs/nfs/nfs4super.c
index 569b166cc050..a5e1a3026d48 100644
--- a/fs/nfs/nfs4super.c
+++ b/fs/nfs/nfs4super.c
@@ -252,6 +252,8 @@ struct dentry *nfs4_try_mount(int flags, const char *dev_name,
252 252
253 dfprintk(MOUNT, "--> nfs4_try_mount()\n"); 253 dfprintk(MOUNT, "--> nfs4_try_mount()\n");
254 254
255 if (data->auth_flavors[0] == RPC_AUTH_MAXFLAVOR)
256 data->auth_flavors[0] = RPC_AUTH_UNIX;
255 export_path = data->nfs_server.export_path; 257 export_path = data->nfs_server.export_path;
256 data->nfs_server.export_path = "/"; 258 data->nfs_server.export_path = "/";
257 root_mnt = nfs_do_root_mount(&nfs4_remote_fs_type, flags, mount_info, 259 root_mnt = nfs_do_root_mount(&nfs4_remote_fs_type, flags, mount_info,
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index c2cbf0d90a31..3c79c5878c6d 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -530,14 +530,10 @@ static int nfs4_stat_to_errno(int);
530 decode_setclientid_maxsz) 530 decode_setclientid_maxsz)
531#define NFS4_enc_setclientid_confirm_sz \ 531#define NFS4_enc_setclientid_confirm_sz \
532 (compound_encode_hdr_maxsz + \ 532 (compound_encode_hdr_maxsz + \
533 encode_setclientid_confirm_maxsz + \ 533 encode_setclientid_confirm_maxsz)
534 encode_putrootfh_maxsz + \
535 encode_fsinfo_maxsz)
536#define NFS4_dec_setclientid_confirm_sz \ 534#define NFS4_dec_setclientid_confirm_sz \
537 (compound_decode_hdr_maxsz + \ 535 (compound_decode_hdr_maxsz + \
538 decode_setclientid_confirm_maxsz + \ 536 decode_setclientid_confirm_maxsz)
539 decode_putrootfh_maxsz + \
540 decode_fsinfo_maxsz)
541#define NFS4_enc_lock_sz (compound_encode_hdr_maxsz + \ 537#define NFS4_enc_lock_sz (compound_encode_hdr_maxsz + \
542 encode_sequence_maxsz + \ 538 encode_sequence_maxsz + \
543 encode_putfh_maxsz + \ 539 encode_putfh_maxsz + \
@@ -2601,12 +2597,9 @@ static void nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req,
2601 struct compound_hdr hdr = { 2597 struct compound_hdr hdr = {
2602 .nops = 0, 2598 .nops = 0,
2603 }; 2599 };
2604 const u32 lease_bitmap[3] = { FATTR4_WORD0_LEASE_TIME };
2605 2600
2606 encode_compound_hdr(xdr, req, &hdr); 2601 encode_compound_hdr(xdr, req, &hdr);
2607 encode_setclientid_confirm(xdr, arg, &hdr); 2602 encode_setclientid_confirm(xdr, arg, &hdr);
2608 encode_putrootfh(xdr, &hdr);
2609 encode_fsinfo(xdr, lease_bitmap, &hdr);
2610 encode_nops(&hdr); 2603 encode_nops(&hdr);
2611} 2604}
2612 2605
@@ -5198,27 +5191,30 @@ static int decode_delegreturn(struct xdr_stream *xdr)
5198 return decode_op_hdr(xdr, OP_DELEGRETURN); 5191 return decode_op_hdr(xdr, OP_DELEGRETURN);
5199} 5192}
5200 5193
5201static int decode_secinfo_gss(struct xdr_stream *xdr, struct nfs4_secinfo_flavor *flavor) 5194static int decode_secinfo_gss(struct xdr_stream *xdr,
5195 struct nfs4_secinfo4 *flavor)
5202{ 5196{
5197 u32 oid_len;
5203 __be32 *p; 5198 __be32 *p;
5204 5199
5205 p = xdr_inline_decode(xdr, 4); 5200 p = xdr_inline_decode(xdr, 4);
5206 if (unlikely(!p)) 5201 if (unlikely(!p))
5207 goto out_overflow; 5202 goto out_overflow;
5208 flavor->gss.sec_oid4.len = be32_to_cpup(p); 5203 oid_len = be32_to_cpup(p);
5209 if (flavor->gss.sec_oid4.len > GSS_OID_MAX_LEN) 5204 if (oid_len > GSS_OID_MAX_LEN)
5210 goto out_err; 5205 goto out_err;
5211 5206
5212 p = xdr_inline_decode(xdr, flavor->gss.sec_oid4.len); 5207 p = xdr_inline_decode(xdr, oid_len);
5213 if (unlikely(!p)) 5208 if (unlikely(!p))
5214 goto out_overflow; 5209 goto out_overflow;
5215 memcpy(flavor->gss.sec_oid4.data, p, flavor->gss.sec_oid4.len); 5210 memcpy(flavor->flavor_info.oid.data, p, oid_len);
5211 flavor->flavor_info.oid.len = oid_len;
5216 5212
5217 p = xdr_inline_decode(xdr, 8); 5213 p = xdr_inline_decode(xdr, 8);
5218 if (unlikely(!p)) 5214 if (unlikely(!p))
5219 goto out_overflow; 5215 goto out_overflow;
5220 flavor->gss.qop4 = be32_to_cpup(p++); 5216 flavor->flavor_info.qop = be32_to_cpup(p++);
5221 flavor->gss.service = be32_to_cpup(p); 5217 flavor->flavor_info.service = be32_to_cpup(p);
5222 5218
5223 return 0; 5219 return 0;
5224 5220
@@ -5231,10 +5227,10 @@ out_err:
5231 5227
5232static int decode_secinfo_common(struct xdr_stream *xdr, struct nfs4_secinfo_res *res) 5228static int decode_secinfo_common(struct xdr_stream *xdr, struct nfs4_secinfo_res *res)
5233{ 5229{
5234 struct nfs4_secinfo_flavor *sec_flavor; 5230 struct nfs4_secinfo4 *sec_flavor;
5231 unsigned int i, num_flavors;
5235 int status; 5232 int status;
5236 __be32 *p; 5233 __be32 *p;
5237 int i, num_flavors;
5238 5234
5239 p = xdr_inline_decode(xdr, 4); 5235 p = xdr_inline_decode(xdr, 4);
5240 if (unlikely(!p)) 5236 if (unlikely(!p))
@@ -6637,8 +6633,7 @@ static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req,
6637 * Decode SETCLIENTID_CONFIRM response 6633 * Decode SETCLIENTID_CONFIRM response
6638 */ 6634 */
6639static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, 6635static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req,
6640 struct xdr_stream *xdr, 6636 struct xdr_stream *xdr)
6641 struct nfs_fsinfo *fsinfo)
6642{ 6637{
6643 struct compound_hdr hdr; 6638 struct compound_hdr hdr;
6644 int status; 6639 int status;
@@ -6646,10 +6641,6 @@ static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req,
6646 status = decode_compound_hdr(xdr, &hdr); 6641 status = decode_compound_hdr(xdr, &hdr);
6647 if (!status) 6642 if (!status)
6648 status = decode_setclientid_confirm(xdr); 6643 status = decode_setclientid_confirm(xdr);
6649 if (!status)
6650 status = decode_putrootfh(xdr);
6651 if (!status)
6652 status = decode_fsinfo(xdr, fsinfo);
6653 return status; 6644 return status;
6654} 6645}
6655 6646
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 17b32b722457..3bb8318f6d0c 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -917,7 +917,7 @@ static struct nfs_parsed_mount_data *nfs_alloc_parsed_mount_data(void)
917 data->mount_server.port = NFS_UNSPEC_PORT; 917 data->mount_server.port = NFS_UNSPEC_PORT;
918 data->nfs_server.port = NFS_UNSPEC_PORT; 918 data->nfs_server.port = NFS_UNSPEC_PORT;
919 data->nfs_server.protocol = XPRT_TRANSPORT_TCP; 919 data->nfs_server.protocol = XPRT_TRANSPORT_TCP;
920 data->auth_flavors[0] = RPC_AUTH_UNIX; 920 data->auth_flavors[0] = RPC_AUTH_MAXFLAVOR;
921 data->auth_flavor_len = 1; 921 data->auth_flavor_len = 1;
922 data->minorversion = 0; 922 data->minorversion = 0;
923 data->need_mount = true; 923 data->need_mount = true;
@@ -1605,49 +1605,57 @@ out_security_failure:
1605} 1605}
1606 1606
1607/* 1607/*
1608 * Match the requested auth flavors with the list returned by 1608 * Select a security flavor for this mount. The selected flavor
1609 * the server. Returns zero and sets the mount's authentication 1609 * is planted in args->auth_flavors[0].
1610 * flavor on success; returns -EACCES if server does not support
1611 * the requested flavor.
1612 */ 1610 */
1613static int nfs_walk_authlist(struct nfs_parsed_mount_data *args, 1611static void nfs_select_flavor(struct nfs_parsed_mount_data *args,
1614 struct nfs_mount_request *request) 1612 struct nfs_mount_request *request)
1615{ 1613{
1616 unsigned int i, j, server_authlist_len = *(request->auth_flav_len); 1614 unsigned int i, count = *(request->auth_flav_len);
1615 rpc_authflavor_t flavor;
1616
1617 if (args->auth_flavors[0] != RPC_AUTH_MAXFLAVOR)
1618 goto out;
1619
1620 /*
1621 * The NFSv2 MNT operation does not return a flavor list.
1622 */
1623 if (args->mount_server.version != NFS_MNT3_VERSION)
1624 goto out_default;
1617 1625
1618 /* 1626 /*
1619 * Certain releases of Linux's mountd return an empty 1627 * Certain releases of Linux's mountd return an empty
1620 * flavor list. To prevent behavioral regression with 1628 * flavor list in some cases.
1621 * these servers (ie. rejecting mounts that used to
1622 * succeed), revert to pre-2.6.32 behavior (no checking)
1623 * if the returned flavor list is empty.
1624 */ 1629 */
1625 if (server_authlist_len == 0) 1630 if (count == 0)
1626 return 0; 1631 goto out_default;
1627 1632
1628 /* 1633 /*
1629 * We avoid sophisticated negotiating here, as there are
1630 * plenty of cases where we can get it wrong, providing
1631 * either too little or too much security.
1632 *
1633 * RFC 2623, section 2.7 suggests we SHOULD prefer the 1634 * RFC 2623, section 2.7 suggests we SHOULD prefer the
1634 * flavor listed first. However, some servers list 1635 * flavor listed first. However, some servers list
1635 * AUTH_NULL first. Our caller plants AUTH_SYS, the 1636 * AUTH_NULL first. Avoid ever choosing AUTH_NULL.
1636 * preferred default, in args->auth_flavors[0] if user
1637 * didn't specify sec= mount option.
1638 */ 1637 */
1639 for (i = 0; i < args->auth_flavor_len; i++) 1638 for (i = 0; i < count; i++) {
1640 for (j = 0; j < server_authlist_len; j++) 1639 struct rpcsec_gss_info info;
1641 if (args->auth_flavors[i] == request->auth_flavs[j]) { 1640
1642 dfprintk(MOUNT, "NFS: using auth flavor %d\n", 1641 flavor = request->auth_flavs[i];
1643 request->auth_flavs[j]); 1642 switch (flavor) {
1644 args->auth_flavors[0] = request->auth_flavs[j]; 1643 case RPC_AUTH_UNIX:
1645 return 0; 1644 goto out_set;
1646 } 1645 case RPC_AUTH_NULL:
1646 continue;
1647 default:
1648 if (rpcauth_get_gssinfo(flavor, &info) == 0)
1649 goto out_set;
1650 }
1651 }
1647 1652
1648 dfprintk(MOUNT, "NFS: server does not support requested auth flavor\n"); 1653out_default:
1649 nfs_umount(request); 1654 flavor = RPC_AUTH_UNIX;
1650 return -EACCES; 1655out_set:
1656 args->auth_flavors[0] = flavor;
1657out:
1658 dfprintk(MOUNT, "NFS: using auth flavor %d\n", args->auth_flavors[0]);
1651} 1659}
1652 1660
1653/* 1661/*
@@ -1710,12 +1718,8 @@ static int nfs_request_mount(struct nfs_parsed_mount_data *args,
1710 return status; 1718 return status;
1711 } 1719 }
1712 1720
1713 /* 1721 nfs_select_flavor(args, &request);
1714 * MNTv1 (NFSv2) does not support auth flavor negotiation. 1722 return 0;
1715 */
1716 if (args->mount_server.version != NFS_MNT3_VERSION)
1717 return 0;
1718 return nfs_walk_authlist(args, &request);
1719} 1723}
1720 1724
1721struct dentry *nfs_try_mount(int flags, const char *dev_name, 1725struct dentry *nfs_try_mount(int flags, const char *dev_name,
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 01168865dd37..2a2745615b42 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -3138,10 +3138,9 @@ nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_
3138 3138
3139static __be32 3139static __be32
3140nfsd4_do_encode_secinfo(struct nfsd4_compoundres *resp, 3140nfsd4_do_encode_secinfo(struct nfsd4_compoundres *resp,
3141 __be32 nfserr,struct svc_export *exp) 3141 __be32 nfserr, struct svc_export *exp)
3142{ 3142{
3143 int i = 0; 3143 u32 i, nflavs;
3144 u32 nflavs;
3145 struct exp_flavor_info *flavs; 3144 struct exp_flavor_info *flavs;
3146 struct exp_flavor_info def_flavs[2]; 3145 struct exp_flavor_info def_flavs[2];
3147 __be32 *p; 3146 __be32 *p;
@@ -3172,30 +3171,29 @@ nfsd4_do_encode_secinfo(struct nfsd4_compoundres *resp,
3172 WRITE32(nflavs); 3171 WRITE32(nflavs);
3173 ADJUST_ARGS(); 3172 ADJUST_ARGS();
3174 for (i = 0; i < nflavs; i++) { 3173 for (i = 0; i < nflavs; i++) {
3175 u32 flav = flavs[i].pseudoflavor; 3174 struct rpcsec_gss_info info;
3176 struct gss_api_mech *gm = gss_mech_get_by_pseudoflavor(flav);
3177 3175
3178 if (gm) { 3176 if (rpcauth_get_gssinfo(flavs[i].pseudoflavor, &info) == 0) {
3179 RESERVE_SPACE(4); 3177 RESERVE_SPACE(4);
3180 WRITE32(RPC_AUTH_GSS); 3178 WRITE32(RPC_AUTH_GSS);
3181 ADJUST_ARGS(); 3179 ADJUST_ARGS();
3182 RESERVE_SPACE(4 + gm->gm_oid.len); 3180 RESERVE_SPACE(4 + info.oid.len);
3183 WRITE32(gm->gm_oid.len); 3181 WRITE32(info.oid.len);
3184 WRITEMEM(gm->gm_oid.data, gm->gm_oid.len); 3182 WRITEMEM(info.oid.data, info.oid.len);
3185 ADJUST_ARGS(); 3183 ADJUST_ARGS();
3186 RESERVE_SPACE(4); 3184 RESERVE_SPACE(4);
3187 WRITE32(0); /* qop */ 3185 WRITE32(info.qop);
3188 ADJUST_ARGS(); 3186 ADJUST_ARGS();
3189 RESERVE_SPACE(4); 3187 RESERVE_SPACE(4);
3190 WRITE32(gss_pseudoflavor_to_service(gm, flav)); 3188 WRITE32(info.service);
3191 ADJUST_ARGS(); 3189 ADJUST_ARGS();
3192 gss_mech_put(gm);
3193 } else { 3190 } else {
3194 RESERVE_SPACE(4); 3191 RESERVE_SPACE(4);
3195 WRITE32(flav); 3192 WRITE32(flavs[i].pseudoflavor);
3196 ADJUST_ARGS(); 3193 ADJUST_ARGS();
3197 } 3194 }
3198 } 3195 }
3196
3199out: 3197out:
3200 if (exp) 3198 if (exp)
3201 exp_put(exp); 3199 exp_put(exp);