diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2013-04-23 15:40:40 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2013-04-23 15:40:40 -0400 |
commit | bd1d421abcaae1b84ba377ea4c33bba31d654199 (patch) | |
tree | 10bf67d7063a95ffd013a9d01a35b906a7d89fcf /fs | |
parent | bdeca1b76cd56cd10a029f0ad2fd9ab6dd7e313d (diff) | |
parent | 79d852bf5e7691dc78cc6322ecd1860c50940785 (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.c | 4 | ||||
-rw-r--r-- | fs/nfs/nfs4namespace.c | 43 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 92 | ||||
-rw-r--r-- | fs/nfs/nfs4state.c | 60 | ||||
-rw-r--r-- | fs/nfs/nfs4super.c | 2 | ||||
-rw-r--r-- | fs/nfs/nfs4xdr.c | 39 | ||||
-rw-r--r-- | fs/nfs/super.c | 80 | ||||
-rw-r--r-- | fs/nfsd/nfs4xdr.c | 24 |
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 | */ | ||
137 | rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *flavors) | 147 | rpc_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 | ||
166 | static rpc_authflavor_t nfs4_negotiate_security(struct inode *inode, struct qstr *name) | 171 | static 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 | */ | ||
2558 | static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle, | 2567 | static 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 | /* | 2600 | static 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 | */ |
2594 | int nfs4_proc_get_rootfh(struct nfs_server *server, struct nfs_fh *fhandle, | 2615 | int 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, | |||
3484 | static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo) | 3505 | static 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 | ||
157 | static 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 | |||
169 | static struct rpc_cred * | 157 | static struct rpc_cred * |
170 | nfs4_get_renew_cred_server_locked(struct nfs_server *server) | 158 | nfs4_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; | ||
1901 | again: | 1871 | again: |
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 | ||
1953 | out_unlock: | 1918 | out_unlock: |
1954 | mutex_unlock(&nfs_clid_init_mutex); | 1919 | mutex_unlock(&nfs_clid_init_mutex); |
1955 | out_free: | ||
1956 | kfree(flavors); | ||
1957 | out: | ||
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 | ||
5201 | static int decode_secinfo_gss(struct xdr_stream *xdr, struct nfs4_secinfo_flavor *flavor) | 5194 | static 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 | ||
5232 | static int decode_secinfo_common(struct xdr_stream *xdr, struct nfs4_secinfo_res *res) | 5228 | static 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 | */ |
6639 | static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, | 6635 | static 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 | */ |
1613 | static int nfs_walk_authlist(struct nfs_parsed_mount_data *args, | 1611 | static 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"); | 1653 | out_default: |
1649 | nfs_umount(request); | 1654 | flavor = RPC_AUTH_UNIX; |
1650 | return -EACCES; | 1655 | out_set: |
1656 | args->auth_flavors[0] = flavor; | ||
1657 | out: | ||
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 | ||
1721 | struct dentry *nfs_try_mount(int flags, const char *dev_name, | 1725 | struct 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 | ||
3139 | static __be32 | 3139 | static __be32 |
3140 | nfsd4_do_encode_secinfo(struct nfsd4_compoundres *resp, | 3140 | nfsd4_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 | |||
3199 | out: | 3197 | out: |
3200 | if (exp) | 3198 | if (exp) |
3201 | exp_put(exp); | 3199 | exp_put(exp); |