aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJ. Bruce Fields <bfields@redhat.com>2013-04-29 14:03:30 -0400
committerJ. Bruce Fields <bfields@redhat.com>2013-04-29 16:23:34 -0400
commitb1df7637232927ac69ed1a32e9c6b768f635b7d4 (patch)
treecf5fdd96cccb3a89f4e0dea895775eb7c428c533
parentdd30333cf5a2f9dfecda5c6f4523133f13847aae (diff)
parent721ccfb79b6f74f4052de70236d24047e73682d4 (diff)
Merge branch 'nfs-for-next' of git://linux-nfs.org/~trondmy/nfs-2.6 into for-3.10
Note conflict: Chuck's patches modified (and made static) gss_mech_get_by_OID, which is still needed by gss-proxy patches. The conflict resolution is a bit minimal; we may want some more cleanup.
-rw-r--r--fs/nfs/nfs4client.c49
-rw-r--r--fs/nfs/nfs4namespace.c43
-rw-r--r--fs/nfs/nfs4proc.c136
-rw-r--r--fs/nfs/nfs4state.c68
-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
-rw-r--r--include/linux/nfs_xdr.h24
-rw-r--r--include/linux/sunrpc/auth.h9
-rw-r--r--include/linux/sunrpc/gss_api.h30
-rw-r--r--net/sunrpc/Kconfig1
-rw-r--r--net/sunrpc/auth.c75
-rw-r--r--net/sunrpc/auth_gss/auth_gss.c3
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_mech.c6
-rw-r--r--net/sunrpc/auth_gss/gss_mech_switch.c119
-rw-r--r--net/sunrpc/auth_gss/gss_rpc_upcall.c7
-rw-r--r--net/sunrpc/auth_gss/gss_rpc_upcall.h3
-rw-r--r--net/sunrpc/auth_gss/svcauth_gss.c4
-rw-r--r--net/sunrpc/clnt.c11
20 files changed, 456 insertions, 277 deletions
diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c
index f4d4d4ec6bf7..947b0c908aa9 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
@@ -302,7 +304,7 @@ int nfs40_walk_client_list(struct nfs_client *new,
302 struct rpc_cred *cred) 304 struct rpc_cred *cred)
303{ 305{
304 struct nfs_net *nn = net_generic(new->cl_net, nfs_net_id); 306 struct nfs_net *nn = net_generic(new->cl_net, nfs_net_id);
305 struct nfs_client *pos, *n, *prev = NULL; 307 struct nfs_client *pos, *prev = NULL;
306 struct nfs4_setclientid_res clid = { 308 struct nfs4_setclientid_res clid = {
307 .clientid = new->cl_clientid, 309 .clientid = new->cl_clientid,
308 .confirm = new->cl_confirm, 310 .confirm = new->cl_confirm,
@@ -310,10 +312,23 @@ int nfs40_walk_client_list(struct nfs_client *new,
310 int status = -NFS4ERR_STALE_CLIENTID; 312 int status = -NFS4ERR_STALE_CLIENTID;
311 313
312 spin_lock(&nn->nfs_client_lock); 314 spin_lock(&nn->nfs_client_lock);
313 list_for_each_entry_safe(pos, n, &nn->nfs_client_list, cl_share_link) { 315 list_for_each_entry(pos, &nn->nfs_client_list, cl_share_link) {
314 /* If "pos" isn't marked ready, we can't trust the 316 /* If "pos" isn't marked ready, we can't trust the
315 * remaining fields in "pos" */ 317 * remaining fields in "pos" */
316 if (pos->cl_cons_state < NFS_CS_READY) 318 if (pos->cl_cons_state > NFS_CS_READY) {
319 atomic_inc(&pos->cl_count);
320 spin_unlock(&nn->nfs_client_lock);
321
322 if (prev)
323 nfs_put_client(prev);
324 prev = pos;
325
326 status = nfs_wait_client_init_complete(pos);
327 spin_lock(&nn->nfs_client_lock);
328 if (status < 0)
329 continue;
330 }
331 if (pos->cl_cons_state != NFS_CS_READY)
317 continue; 332 continue;
318 333
319 if (pos->rpc_ops != new->rpc_ops) 334 if (pos->rpc_ops != new->rpc_ops)
@@ -425,16 +440,16 @@ int nfs41_walk_client_list(struct nfs_client *new,
425 struct rpc_cred *cred) 440 struct rpc_cred *cred)
426{ 441{
427 struct nfs_net *nn = net_generic(new->cl_net, nfs_net_id); 442 struct nfs_net *nn = net_generic(new->cl_net, nfs_net_id);
428 struct nfs_client *pos, *n, *prev = NULL; 443 struct nfs_client *pos, *prev = NULL;
429 int status = -NFS4ERR_STALE_CLIENTID; 444 int status = -NFS4ERR_STALE_CLIENTID;
430 445
431 spin_lock(&nn->nfs_client_lock); 446 spin_lock(&nn->nfs_client_lock);
432 list_for_each_entry_safe(pos, n, &nn->nfs_client_list, cl_share_link) { 447 list_for_each_entry(pos, &nn->nfs_client_list, cl_share_link) {
433 /* If "pos" isn't marked ready, we can't trust the 448 /* If "pos" isn't marked ready, we can't trust the
434 * remaining fields in "pos", especially the client 449 * remaining fields in "pos", especially the client
435 * ID and serverowner fields. Wait for CREATE_SESSION 450 * ID and serverowner fields. Wait for CREATE_SESSION
436 * to finish. */ 451 * to finish. */
437 if (pos->cl_cons_state < NFS_CS_READY) { 452 if (pos->cl_cons_state > NFS_CS_READY) {
438 atomic_inc(&pos->cl_count); 453 atomic_inc(&pos->cl_count);
439 spin_unlock(&nn->nfs_client_lock); 454 spin_unlock(&nn->nfs_client_lock);
440 455
@@ -442,18 +457,17 @@ int nfs41_walk_client_list(struct nfs_client *new,
442 nfs_put_client(prev); 457 nfs_put_client(prev);
443 prev = pos; 458 prev = pos;
444 459
445 nfs4_schedule_lease_recovery(pos);
446 status = nfs_wait_client_init_complete(pos); 460 status = nfs_wait_client_init_complete(pos);
447 if (status < 0) { 461 if (status == 0) {
448 nfs_put_client(pos); 462 nfs4_schedule_lease_recovery(pos);
449 spin_lock(&nn->nfs_client_lock); 463 status = nfs4_wait_clnt_recover(pos);
450 continue;
451 } 464 }
452 status = pos->cl_cons_state;
453 spin_lock(&nn->nfs_client_lock); 465 spin_lock(&nn->nfs_client_lock);
454 if (status < 0) 466 if (status < 0)
455 continue; 467 continue;
456 } 468 }
469 if (pos->cl_cons_state != NFS_CS_READY)
470 continue;
457 471
458 if (pos->rpc_ops != new->rpc_ops) 472 if (pos->rpc_ops != new->rpc_ops)
459 continue; 473 continue;
@@ -471,17 +485,18 @@ int nfs41_walk_client_list(struct nfs_client *new,
471 continue; 485 continue;
472 486
473 atomic_inc(&pos->cl_count); 487 atomic_inc(&pos->cl_count);
474 spin_unlock(&nn->nfs_client_lock); 488 *result = pos;
489 status = 0;
475 dprintk("NFS: <-- %s using nfs_client = %p ({%d})\n", 490 dprintk("NFS: <-- %s using nfs_client = %p ({%d})\n",
476 __func__, pos, atomic_read(&pos->cl_count)); 491 __func__, pos, atomic_read(&pos->cl_count));
477 492 break;
478 *result = pos;
479 return 0;
480 } 493 }
481 494
482 /* No matching nfs_client found. */ 495 /* No matching nfs_client found. */
483 spin_unlock(&nn->nfs_client_lock); 496 spin_unlock(&nn->nfs_client_lock);
484 dprintk("NFS: <-- %s status = %d\n", __func__, status); 497 dprintk("NFS: <-- %s status = %d\n", __func__, status);
498 if (prev)
499 nfs_put_client(prev);
485 return status; 500 return status;
486} 501}
487#endif /* CONFIG_NFS_V4_1 */ 502#endif /* CONFIG_NFS_V4_1 */
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 c13144911d20..9da4bd55eb30 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -769,6 +769,7 @@ struct nfs4_opendata {
769 struct iattr attrs; 769 struct iattr attrs;
770 unsigned long timestamp; 770 unsigned long timestamp;
771 unsigned int rpc_done : 1; 771 unsigned int rpc_done : 1;
772 unsigned int is_recover : 1;
772 int rpc_status; 773 int rpc_status;
773 int cancelled; 774 int cancelled;
774}; 775};
@@ -1101,9 +1102,12 @@ static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata)
1101 /* Save the delegation */ 1102 /* Save the delegation */
1102 nfs4_stateid_copy(&stateid, &delegation->stateid); 1103 nfs4_stateid_copy(&stateid, &delegation->stateid);
1103 rcu_read_unlock(); 1104 rcu_read_unlock();
1104 ret = nfs_may_open(state->inode, state->owner->so_cred, open_mode); 1105 nfs_release_seqid(opendata->o_arg.seqid);
1105 if (ret != 0) 1106 if (!opendata->is_recover) {
1106 goto out; 1107 ret = nfs_may_open(state->inode, state->owner->so_cred, open_mode);
1108 if (ret != 0)
1109 goto out;
1110 }
1107 ret = -EAGAIN; 1111 ret = -EAGAIN;
1108 1112
1109 /* Try to update the stateid using the delegation */ 1113 /* Try to update the stateid using the delegation */
@@ -1543,15 +1547,20 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata)
1543 rcu_read_lock(); 1547 rcu_read_lock();
1544 delegation = rcu_dereference(NFS_I(data->state->inode)->delegation); 1548 delegation = rcu_dereference(NFS_I(data->state->inode)->delegation);
1545 if (data->o_arg.claim != NFS4_OPEN_CLAIM_DELEGATE_CUR && 1549 if (data->o_arg.claim != NFS4_OPEN_CLAIM_DELEGATE_CUR &&
1550 data->o_arg.claim != NFS4_OPEN_CLAIM_DELEG_CUR_FH &&
1546 can_open_delegated(delegation, data->o_arg.fmode)) 1551 can_open_delegated(delegation, data->o_arg.fmode))
1547 goto unlock_no_action; 1552 goto unlock_no_action;
1548 rcu_read_unlock(); 1553 rcu_read_unlock();
1549 } 1554 }
1550 /* Update client id. */ 1555 /* Update client id. */
1551 data->o_arg.clientid = clp->cl_clientid; 1556 data->o_arg.clientid = clp->cl_clientid;
1552 if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS) { 1557 switch (data->o_arg.claim) {
1553 task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR]; 1558 case NFS4_OPEN_CLAIM_PREVIOUS:
1559 case NFS4_OPEN_CLAIM_DELEG_CUR_FH:
1560 case NFS4_OPEN_CLAIM_DELEG_PREV_FH:
1554 data->o_arg.open_bitmap = &nfs4_open_noattr_bitmap[0]; 1561 data->o_arg.open_bitmap = &nfs4_open_noattr_bitmap[0];
1562 case NFS4_OPEN_CLAIM_FH:
1563 task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR];
1555 nfs_copy_fh(&data->o_res.fh, data->o_arg.fh); 1564 nfs_copy_fh(&data->o_res.fh, data->o_arg.fh);
1556 } 1565 }
1557 data->timestamp = jiffies; 1566 data->timestamp = jiffies;
@@ -1665,8 +1674,11 @@ static int nfs4_run_open_task(struct nfs4_opendata *data, int isrecover)
1665 data->rpc_done = 0; 1674 data->rpc_done = 0;
1666 data->rpc_status = 0; 1675 data->rpc_status = 0;
1667 data->cancelled = 0; 1676 data->cancelled = 0;
1668 if (isrecover) 1677 data->is_recover = 0;
1678 if (isrecover) {
1669 nfs4_set_sequence_privileged(&o_arg->seq_args); 1679 nfs4_set_sequence_privileged(&o_arg->seq_args);
1680 data->is_recover = 1;
1681 }
1670 task = rpc_run_task(&task_setup_data); 1682 task = rpc_run_task(&task_setup_data);
1671 if (IS_ERR(task)) 1683 if (IS_ERR(task))
1672 return PTR_ERR(task); 1684 return PTR_ERR(task);
@@ -2130,20 +2142,25 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
2130 .rpc_cred = cred, 2142 .rpc_cred = cred,
2131 }; 2143 };
2132 unsigned long timestamp = jiffies; 2144 unsigned long timestamp = jiffies;
2145 fmode_t fmode;
2146 bool truncate;
2133 int status; 2147 int status;
2134 2148
2135 nfs_fattr_init(fattr); 2149 nfs_fattr_init(fattr);
2136 2150
2137 if (state != NULL && nfs4_valid_open_stateid(state)) { 2151 /* Servers should only apply open mode checks for file size changes */
2152 truncate = (sattr->ia_valid & ATTR_SIZE) ? true : false;
2153 fmode = truncate ? FMODE_WRITE : FMODE_READ;
2154
2155 if (nfs4_copy_delegation_stateid(&arg.stateid, inode, fmode)) {
2156 /* Use that stateid */
2157 } else if (truncate && state != NULL && nfs4_valid_open_stateid(state)) {
2138 struct nfs_lockowner lockowner = { 2158 struct nfs_lockowner lockowner = {
2139 .l_owner = current->files, 2159 .l_owner = current->files,
2140 .l_pid = current->tgid, 2160 .l_pid = current->tgid,
2141 }; 2161 };
2142 nfs4_select_rw_stateid(&arg.stateid, state, FMODE_WRITE, 2162 nfs4_select_rw_stateid(&arg.stateid, state, FMODE_WRITE,
2143 &lockowner); 2163 &lockowner);
2144 } else if (nfs4_copy_delegation_stateid(&arg.stateid, inode,
2145 FMODE_WRITE)) {
2146 /* Use that stateid */
2147 } else 2164 } else
2148 nfs4_stateid_copy(&arg.stateid, &zero_stateid); 2165 nfs4_stateid_copy(&arg.stateid, &zero_stateid);
2149 2166
@@ -2167,6 +2184,13 @@ static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
2167 err = _nfs4_do_setattr(inode, cred, fattr, sattr, state); 2184 err = _nfs4_do_setattr(inode, cred, fattr, sattr, state);
2168 switch (err) { 2185 switch (err) {
2169 case -NFS4ERR_OPENMODE: 2186 case -NFS4ERR_OPENMODE:
2187 if (!(sattr->ia_valid & ATTR_SIZE)) {
2188 pr_warn_once("NFSv4: server %s is incorrectly "
2189 "applying open mode checks to "
2190 "a SETATTR that is not "
2191 "changing file size.\n",
2192 server->nfs_client->cl_hostname);
2193 }
2170 if (state && !(state->state & FMODE_WRITE)) { 2194 if (state && !(state->state & FMODE_WRITE)) {
2171 err = -EBADF; 2195 err = -EBADF;
2172 if (sattr->ia_valid & ATTR_OPEN) 2196 if (sattr->ia_valid & ATTR_OPEN)
@@ -2536,7 +2560,7 @@ static int nfs4_lookup_root_sec(struct nfs_server *server, struct nfs_fh *fhandl
2536 2560
2537 auth = rpcauth_create(flavor, server->client); 2561 auth = rpcauth_create(flavor, server->client);
2538 if (IS_ERR(auth)) { 2562 if (IS_ERR(auth)) {
2539 ret = -EIO; 2563 ret = -EACCES;
2540 goto out; 2564 goto out;
2541 } 2565 }
2542 ret = nfs4_lookup_root(server, fhandle, info); 2566 ret = nfs4_lookup_root(server, fhandle, info);
@@ -2544,27 +2568,36 @@ out:
2544 return ret; 2568 return ret;
2545} 2569}
2546 2570
2571/*
2572 * Retry pseudoroot lookup with various security flavors. We do this when:
2573 *
2574 * NFSv4.0: the PUTROOTFH operation returns NFS4ERR_WRONGSEC
2575 * NFSv4.1: the server does not support the SECINFO_NO_NAME operation
2576 *
2577 * Returns zero on success, or a negative NFS4ERR value, or a
2578 * negative errno value.
2579 */
2547static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle, 2580static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
2548 struct nfs_fsinfo *info) 2581 struct nfs_fsinfo *info)
2549{ 2582{
2550 int i, len, status = 0; 2583 /* Per 3530bis 15.33.5 */
2551 rpc_authflavor_t flav_array[NFS_MAX_SECFLAVORS]; 2584 static const rpc_authflavor_t flav_array[] = {
2552 2585 RPC_AUTH_GSS_KRB5P,
2553 len = rpcauth_list_flavors(flav_array, ARRAY_SIZE(flav_array)); 2586 RPC_AUTH_GSS_KRB5I,
2554 if (len < 0) 2587 RPC_AUTH_GSS_KRB5,
2555 return len; 2588 RPC_AUTH_UNIX, /* courtesy */
2556 2589 RPC_AUTH_NULL,
2557 for (i = 0; i < len; i++) { 2590 };
2558 /* AUTH_UNIX is the default flavor if none was specified, 2591 int status = -EPERM;
2559 * thus has already been tried. */ 2592 size_t i;
2560 if (flav_array[i] == RPC_AUTH_UNIX)
2561 continue;
2562 2593
2594 for (i = 0; i < ARRAY_SIZE(flav_array); i++) {
2563 status = nfs4_lookup_root_sec(server, fhandle, info, flav_array[i]); 2595 status = nfs4_lookup_root_sec(server, fhandle, info, flav_array[i]);
2564 if (status == -NFS4ERR_WRONGSEC || status == -EACCES) 2596 if (status == -NFS4ERR_WRONGSEC || status == -EACCES)
2565 continue; 2597 continue;
2566 break; 2598 break;
2567 } 2599 }
2600
2568 /* 2601 /*
2569 * -EACCESS could mean that the user doesn't have correct permissions 2602 * -EACCESS could mean that the user doesn't have correct permissions
2570 * to access the mount. It could also mean that we tried to mount 2603 * to access the mount. It could also mean that we tried to mount
@@ -2577,24 +2610,36 @@ static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
2577 return status; 2610 return status;
2578} 2611}
2579 2612
2580/* 2613static int nfs4_do_find_root_sec(struct nfs_server *server,
2581 * get the file handle for the "/" directory on the server 2614 struct nfs_fh *fhandle, struct nfs_fsinfo *info)
2615{
2616 int mv = server->nfs_client->cl_minorversion;
2617 return nfs_v4_minor_ops[mv]->find_root_sec(server, fhandle, info);
2618}
2619
2620/**
2621 * nfs4_proc_get_rootfh - get file handle for server's pseudoroot
2622 * @server: initialized nfs_server handle
2623 * @fhandle: we fill in the pseudo-fs root file handle
2624 * @info: we fill in an FSINFO struct
2625 *
2626 * Returns zero on success, or a negative errno.
2582 */ 2627 */
2583int nfs4_proc_get_rootfh(struct nfs_server *server, struct nfs_fh *fhandle, 2628int nfs4_proc_get_rootfh(struct nfs_server *server, struct nfs_fh *fhandle,
2584 struct nfs_fsinfo *info) 2629 struct nfs_fsinfo *info)
2585{ 2630{
2586 int minor_version = server->nfs_client->cl_minorversion; 2631 int status;
2587 int status = nfs4_lookup_root(server, fhandle, info); 2632
2588 if ((status == -NFS4ERR_WRONGSEC) && !(server->flags & NFS_MOUNT_SECFLAVOUR)) 2633 status = nfs4_lookup_root(server, fhandle, info);
2589 /* 2634 if ((status == -NFS4ERR_WRONGSEC) &&
2590 * A status of -NFS4ERR_WRONGSEC will be mapped to -EPERM 2635 !(server->flags & NFS_MOUNT_SECFLAVOUR))
2591 * by nfs4_map_errors() as this function exits. 2636 status = nfs4_do_find_root_sec(server, fhandle, info);
2592 */ 2637
2593 status = nfs_v4_minor_ops[minor_version]->find_root_sec(server, fhandle, info);
2594 if (status == 0) 2638 if (status == 0)
2595 status = nfs4_server_capabilities(server, fhandle); 2639 status = nfs4_server_capabilities(server, fhandle);
2596 if (status == 0) 2640 if (status == 0)
2597 status = nfs4_do_fsinfo(server, fhandle, info); 2641 status = nfs4_do_fsinfo(server, fhandle, info);
2642
2598 return nfs4_map_errors(status); 2643 return nfs4_map_errors(status);
2599} 2644}
2600 2645
@@ -3473,12 +3518,21 @@ static int _nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle,
3473static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo) 3518static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo)
3474{ 3519{
3475 struct nfs4_exception exception = { }; 3520 struct nfs4_exception exception = { };
3521 unsigned long now = jiffies;
3476 int err; 3522 int err;
3477 3523
3478 do { 3524 do {
3479 err = nfs4_handle_exception(server, 3525 err = _nfs4_do_fsinfo(server, fhandle, fsinfo);
3480 _nfs4_do_fsinfo(server, fhandle, fsinfo), 3526 if (err == 0) {
3481 &exception); 3527 struct nfs_client *clp = server->nfs_client;
3528
3529 spin_lock(&clp->cl_lock);
3530 clp->cl_lease_time = fsinfo->lease_time * HZ;
3531 clp->cl_last_renewal = now;
3532 spin_unlock(&clp->cl_lock);
3533 break;
3534 }
3535 err = nfs4_handle_exception(server, err, &exception);
3482 } while (exception.retry); 3536 } while (exception.retry);
3483 return err; 3537 return err;
3484} 3538}
@@ -4319,27 +4373,17 @@ int nfs4_proc_setclientid_confirm(struct nfs_client *clp,
4319 struct nfs4_setclientid_res *arg, 4373 struct nfs4_setclientid_res *arg,
4320 struct rpc_cred *cred) 4374 struct rpc_cred *cred)
4321{ 4375{
4322 struct nfs_fsinfo fsinfo;
4323 struct rpc_message msg = { 4376 struct rpc_message msg = {
4324 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETCLIENTID_CONFIRM], 4377 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETCLIENTID_CONFIRM],
4325 .rpc_argp = arg, 4378 .rpc_argp = arg,
4326 .rpc_resp = &fsinfo,
4327 .rpc_cred = cred, 4379 .rpc_cred = cred,
4328 }; 4380 };
4329 unsigned long now;
4330 int status; 4381 int status;
4331 4382
4332 dprintk("NFS call setclientid_confirm auth=%s, (client ID %llx)\n", 4383 dprintk("NFS call setclientid_confirm auth=%s, (client ID %llx)\n",
4333 clp->cl_rpcclient->cl_auth->au_ops->au_name, 4384 clp->cl_rpcclient->cl_auth->au_ops->au_name,
4334 clp->cl_clientid); 4385 clp->cl_clientid);
4335 now = jiffies;
4336 status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT); 4386 status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
4337 if (status == 0) {
4338 spin_lock(&clp->cl_lock);
4339 clp->cl_lease_time = fsinfo.lease_time * HZ;
4340 clp->cl_last_renewal = now;
4341 spin_unlock(&clp->cl_lock);
4342 }
4343 dprintk("NFS reply setclientid_confirm: %d\n", status); 4387 dprintk("NFS reply setclientid_confirm: %d\n", status);
4344 return status; 4388 return status;
4345} 4389}
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index b7796950eceb..0b32f9483b7a 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,22 +1887,23 @@ 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;
1939 } 1899 }
1940 clp->cl_rpcclient = clnt; 1900 /* Note: this is safe because we haven't yet marked the
1901 * client as ready, so we are the only user of
1902 * clp->cl_rpcclient
1903 */
1904 clnt = xchg(&clp->cl_rpcclient, clnt);
1905 rpc_shutdown_client(clnt);
1906 clnt = clp->cl_rpcclient;
1941 goto again; 1907 goto again;
1942 1908
1943 case -NFS4ERR_MINOR_VERS_MISMATCH: 1909 case -NFS4ERR_MINOR_VERS_MISMATCH:
@@ -1948,13 +1914,15 @@ again:
1948 case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery 1914 case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery
1949 * in nfs4_exchange_id */ 1915 * in nfs4_exchange_id */
1950 status = -EKEYEXPIRED; 1916 status = -EKEYEXPIRED;
1917 break;
1918 default:
1919 pr_warn("NFS: %s unhandled error %d. Exiting with error EIO\n",
1920 __func__, status);
1921 status = -EIO;
1951 } 1922 }
1952 1923
1953out_unlock: 1924out_unlock:
1954 mutex_unlock(&nfs_clid_init_mutex); 1925 mutex_unlock(&nfs_clid_init_mutex);
1955out_free:
1956 kfree(flavors);
1957out:
1958 dprintk("NFS: %s: status = %d\n", __func__, status); 1926 dprintk("NFS: %s: status = %d\n", __func__, status);
1959 return status; 1927 return status;
1960} 1928}
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 2f8a29db0f1b..eb494f6a4c6b 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -920,7 +920,7 @@ static struct nfs_parsed_mount_data *nfs_alloc_parsed_mount_data(void)
920 data->mount_server.port = NFS_UNSPEC_PORT; 920 data->mount_server.port = NFS_UNSPEC_PORT;
921 data->nfs_server.port = NFS_UNSPEC_PORT; 921 data->nfs_server.port = NFS_UNSPEC_PORT;
922 data->nfs_server.protocol = XPRT_TRANSPORT_TCP; 922 data->nfs_server.protocol = XPRT_TRANSPORT_TCP;
923 data->auth_flavors[0] = RPC_AUTH_UNIX; 923 data->auth_flavors[0] = RPC_AUTH_MAXFLAVOR;
924 data->auth_flavor_len = 1; 924 data->auth_flavor_len = 1;
925 data->minorversion = 0; 925 data->minorversion = 0;
926 data->need_mount = true; 926 data->need_mount = true;
@@ -1608,49 +1608,57 @@ out_security_failure:
1608} 1608}
1609 1609
1610/* 1610/*
1611 * Match the requested auth flavors with the list returned by 1611 * Select a security flavor for this mount. The selected flavor
1612 * the server. Returns zero and sets the mount's authentication 1612 * is planted in args->auth_flavors[0].
1613 * flavor on success; returns -EACCES if server does not support
1614 * the requested flavor.
1615 */ 1613 */
1616static int nfs_walk_authlist(struct nfs_parsed_mount_data *args, 1614static void nfs_select_flavor(struct nfs_parsed_mount_data *args,
1617 struct nfs_mount_request *request) 1615 struct nfs_mount_request *request)
1618{ 1616{
1619 unsigned int i, j, server_authlist_len = *(request->auth_flav_len); 1617 unsigned int i, count = *(request->auth_flav_len);
1618 rpc_authflavor_t flavor;
1619
1620 if (args->auth_flavors[0] != RPC_AUTH_MAXFLAVOR)
1621 goto out;
1622
1623 /*
1624 * The NFSv2 MNT operation does not return a flavor list.
1625 */
1626 if (args->mount_server.version != NFS_MNT3_VERSION)
1627 goto out_default;
1620 1628
1621 /* 1629 /*
1622 * Certain releases of Linux's mountd return an empty 1630 * Certain releases of Linux's mountd return an empty
1623 * flavor list. To prevent behavioral regression with 1631 * flavor list in some cases.
1624 * these servers (ie. rejecting mounts that used to
1625 * succeed), revert to pre-2.6.32 behavior (no checking)
1626 * if the returned flavor list is empty.
1627 */ 1632 */
1628 if (server_authlist_len == 0) 1633 if (count == 0)
1629 return 0; 1634 goto out_default;
1630 1635
1631 /* 1636 /*
1632 * We avoid sophisticated negotiating here, as there are
1633 * plenty of cases where we can get it wrong, providing
1634 * either too little or too much security.
1635 *
1636 * RFC 2623, section 2.7 suggests we SHOULD prefer the 1637 * RFC 2623, section 2.7 suggests we SHOULD prefer the
1637 * flavor listed first. However, some servers list 1638 * flavor listed first. However, some servers list
1638 * AUTH_NULL first. Our caller plants AUTH_SYS, the 1639 * AUTH_NULL first. Avoid ever choosing AUTH_NULL.
1639 * preferred default, in args->auth_flavors[0] if user
1640 * didn't specify sec= mount option.
1641 */ 1640 */
1642 for (i = 0; i < args->auth_flavor_len; i++) 1641 for (i = 0; i < count; i++) {
1643 for (j = 0; j < server_authlist_len; j++) 1642 struct rpcsec_gss_info info;
1644 if (args->auth_flavors[i] == request->auth_flavs[j]) { 1643
1645 dfprintk(MOUNT, "NFS: using auth flavor %d\n", 1644 flavor = request->auth_flavs[i];
1646 request->auth_flavs[j]); 1645 switch (flavor) {
1647 args->auth_flavors[0] = request->auth_flavs[j]; 1646 case RPC_AUTH_UNIX:
1648 return 0; 1647 goto out_set;
1649 } 1648 case RPC_AUTH_NULL:
1649 continue;
1650 default:
1651 if (rpcauth_get_gssinfo(flavor, &info) == 0)
1652 goto out_set;
1653 }
1654 }
1650 1655
1651 dfprintk(MOUNT, "NFS: server does not support requested auth flavor\n"); 1656out_default:
1652 nfs_umount(request); 1657 flavor = RPC_AUTH_UNIX;
1653 return -EACCES; 1658out_set:
1659 args->auth_flavors[0] = flavor;
1660out:
1661 dfprintk(MOUNT, "NFS: using auth flavor %d\n", args->auth_flavors[0]);
1654} 1662}
1655 1663
1656/* 1664/*
@@ -1713,12 +1721,8 @@ static int nfs_request_mount(struct nfs_parsed_mount_data *args,
1713 return status; 1721 return status;
1714 } 1722 }
1715 1723
1716 /* 1724 nfs_select_flavor(args, &request);
1717 * MNTv1 (NFSv2) does not support auth flavor negotiation. 1725 return 0;
1718 */
1719 if (args->mount_server.version != NFS_MNT3_VERSION)
1720 return 0;
1721 return nfs_walk_authlist(args, &request);
1722} 1726}
1723 1727
1724struct dentry *nfs_try_mount(int flags, const char *dev_name, 1728struct dentry *nfs_try_mount(int flags, const char *dev_name,
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 888a600dad8c..78272185a13d 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -3083,10 +3083,9 @@ nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_
3083 3083
3084static __be32 3084static __be32
3085nfsd4_do_encode_secinfo(struct nfsd4_compoundres *resp, 3085nfsd4_do_encode_secinfo(struct nfsd4_compoundres *resp,
3086 __be32 nfserr,struct svc_export *exp) 3086 __be32 nfserr, struct svc_export *exp)
3087{ 3087{
3088 int i = 0; 3088 u32 i, nflavs;
3089 u32 nflavs;
3090 struct exp_flavor_info *flavs; 3089 struct exp_flavor_info *flavs;
3091 struct exp_flavor_info def_flavs[2]; 3090 struct exp_flavor_info def_flavs[2];
3092 __be32 *p; 3091 __be32 *p;
@@ -3117,30 +3116,29 @@ nfsd4_do_encode_secinfo(struct nfsd4_compoundres *resp,
3117 WRITE32(nflavs); 3116 WRITE32(nflavs);
3118 ADJUST_ARGS(); 3117 ADJUST_ARGS();
3119 for (i = 0; i < nflavs; i++) { 3118 for (i = 0; i < nflavs; i++) {
3120 u32 flav = flavs[i].pseudoflavor; 3119 struct rpcsec_gss_info info;
3121 struct gss_api_mech *gm = gss_mech_get_by_pseudoflavor(flav);
3122 3120
3123 if (gm) { 3121 if (rpcauth_get_gssinfo(flavs[i].pseudoflavor, &info) == 0) {
3124 RESERVE_SPACE(4); 3122 RESERVE_SPACE(4);
3125 WRITE32(RPC_AUTH_GSS); 3123 WRITE32(RPC_AUTH_GSS);
3126 ADJUST_ARGS(); 3124 ADJUST_ARGS();
3127 RESERVE_SPACE(4 + gm->gm_oid.len); 3125 RESERVE_SPACE(4 + info.oid.len);
3128 WRITE32(gm->gm_oid.len); 3126 WRITE32(info.oid.len);
3129 WRITEMEM(gm->gm_oid.data, gm->gm_oid.len); 3127 WRITEMEM(info.oid.data, info.oid.len);
3130 ADJUST_ARGS(); 3128 ADJUST_ARGS();
3131 RESERVE_SPACE(4); 3129 RESERVE_SPACE(4);
3132 WRITE32(0); /* qop */ 3130 WRITE32(info.qop);
3133 ADJUST_ARGS(); 3131 ADJUST_ARGS();
3134 RESERVE_SPACE(4); 3132 RESERVE_SPACE(4);
3135 WRITE32(gss_pseudoflavor_to_service(gm, flav)); 3133 WRITE32(info.service);
3136 ADJUST_ARGS(); 3134 ADJUST_ARGS();
3137 gss_mech_put(gm);
3138 } else { 3135 } else {
3139 RESERVE_SPACE(4); 3136 RESERVE_SPACE(4);
3140 WRITE32(flav); 3137 WRITE32(flavs[i].pseudoflavor);
3141 ADJUST_ARGS(); 3138 ADJUST_ARGS();
3142 } 3139 }
3143 } 3140 }
3141
3144out: 3142out:
3145 if (exp) 3143 if (exp)
3146 exp_put(exp); 3144 exp_put(exp);
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index bdc100f66dfb..766c5bc9d441 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -14,9 +14,6 @@
14#define NFS_DEF_FILE_IO_SIZE (4096U) 14#define NFS_DEF_FILE_IO_SIZE (4096U)
15#define NFS_MIN_FILE_IO_SIZE (1024U) 15#define NFS_MIN_FILE_IO_SIZE (1024U)
16 16
17/* Forward declaration for NFS v3 */
18struct nfs4_secinfo_flavors;
19
20struct nfs4_string { 17struct nfs4_string {
21 unsigned int len; 18 unsigned int len;
22 char *data; 19 char *data;
@@ -1053,25 +1050,14 @@ struct nfs4_fs_locations_res {
1053 struct nfs4_fs_locations *fs_locations; 1050 struct nfs4_fs_locations *fs_locations;
1054}; 1051};
1055 1052
1056struct nfs4_secinfo_oid { 1053struct nfs4_secinfo4 {
1057 unsigned int len; 1054 u32 flavor;
1058 char data[GSS_OID_MAX_LEN]; 1055 struct rpcsec_gss_info flavor_info;
1059};
1060
1061struct nfs4_secinfo_gss {
1062 struct nfs4_secinfo_oid sec_oid4;
1063 unsigned int qop4;
1064 unsigned int service;
1065};
1066
1067struct nfs4_secinfo_flavor {
1068 unsigned int flavor;
1069 struct nfs4_secinfo_gss gss;
1070}; 1056};
1071 1057
1072struct nfs4_secinfo_flavors { 1058struct nfs4_secinfo_flavors {
1073 unsigned int num_flavors; 1059 unsigned int num_flavors;
1074 struct nfs4_secinfo_flavor flavors[0]; 1060 struct nfs4_secinfo4 flavors[0];
1075}; 1061};
1076 1062
1077struct nfs4_secinfo_arg { 1063struct nfs4_secinfo_arg {
diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h
index 58fda1c3c783..0dd00f4f6810 100644
--- a/include/linux/sunrpc/auth.h
+++ b/include/linux/sunrpc/auth.h
@@ -22,6 +22,8 @@
22/* size of the nodename buffer */ 22/* size of the nodename buffer */
23#define UNX_MAXNODENAME 32 23#define UNX_MAXNODENAME 32
24 24
25struct rpcsec_gss_info;
26
25/* Work around the lack of a VFS credential */ 27/* Work around the lack of a VFS credential */
26struct auth_cred { 28struct auth_cred {
27 kuid_t uid; 29 kuid_t uid;
@@ -103,6 +105,9 @@ struct rpc_authops {
103 int (*pipes_create)(struct rpc_auth *); 105 int (*pipes_create)(struct rpc_auth *);
104 void (*pipes_destroy)(struct rpc_auth *); 106 void (*pipes_destroy)(struct rpc_auth *);
105 int (*list_pseudoflavors)(rpc_authflavor_t *, int); 107 int (*list_pseudoflavors)(rpc_authflavor_t *, int);
108 rpc_authflavor_t (*info2flavor)(struct rpcsec_gss_info *);
109 int (*flavor2info)(rpc_authflavor_t,
110 struct rpcsec_gss_info *);
106}; 111};
107 112
108struct rpc_credops { 113struct rpc_credops {
@@ -137,6 +142,10 @@ int rpcauth_register(const struct rpc_authops *);
137int rpcauth_unregister(const struct rpc_authops *); 142int rpcauth_unregister(const struct rpc_authops *);
138struct rpc_auth * rpcauth_create(rpc_authflavor_t, struct rpc_clnt *); 143struct rpc_auth * rpcauth_create(rpc_authflavor_t, struct rpc_clnt *);
139void rpcauth_release(struct rpc_auth *); 144void rpcauth_release(struct rpc_auth *);
145rpc_authflavor_t rpcauth_get_pseudoflavor(rpc_authflavor_t,
146 struct rpcsec_gss_info *);
147int rpcauth_get_gssinfo(rpc_authflavor_t,
148 struct rpcsec_gss_info *);
140int rpcauth_list_flavors(rpc_authflavor_t *, int); 149int rpcauth_list_flavors(rpc_authflavor_t *, int);
141struct rpc_cred * rpcauth_lookup_credcache(struct rpc_auth *, struct auth_cred *, int); 150struct rpc_cred * rpcauth_lookup_credcache(struct rpc_auth *, struct auth_cred *, int);
142void rpcauth_init_cred(struct rpc_cred *, const struct auth_cred *, struct rpc_auth *, const struct rpc_credops *); 151void rpcauth_init_cred(struct rpc_cred *, const struct auth_cred *, struct rpc_auth *, const struct rpc_credops *);
diff --git a/include/linux/sunrpc/gss_api.h b/include/linux/sunrpc/gss_api.h
index 04d03bb2de5d..161463e59624 100644
--- a/include/linux/sunrpc/gss_api.h
+++ b/include/linux/sunrpc/gss_api.h
@@ -25,10 +25,21 @@ struct gss_ctx {
25 25
26#define GSS_C_NO_BUFFER ((struct xdr_netobj) 0) 26#define GSS_C_NO_BUFFER ((struct xdr_netobj) 0)
27#define GSS_C_NO_CONTEXT ((struct gss_ctx *) 0) 27#define GSS_C_NO_CONTEXT ((struct gss_ctx *) 0)
28#define GSS_C_NULL_OID ((struct xdr_netobj) 0) 28#define GSS_C_QOP_DEFAULT (0)
29 29
30/*XXX arbitrary length - is this set somewhere? */ 30/*XXX arbitrary length - is this set somewhere? */
31#define GSS_OID_MAX_LEN 32 31#define GSS_OID_MAX_LEN 32
32struct rpcsec_gss_oid {
33 unsigned int len;
34 u8 data[GSS_OID_MAX_LEN];
35};
36
37/* From RFC 3530 */
38struct rpcsec_gss_info {
39 struct rpcsec_gss_oid oid;
40 u32 qop;
41 u32 service;
42};
32 43
33/* gss-api prototypes; note that these are somewhat simplified versions of 44/* gss-api prototypes; note that these are somewhat simplified versions of
34 * the prototypes specified in RFC 2744. */ 45 * the prototypes specified in RFC 2744. */
@@ -59,12 +70,14 @@ u32 gss_unwrap(
59u32 gss_delete_sec_context( 70u32 gss_delete_sec_context(
60 struct gss_ctx **ctx_id); 71 struct gss_ctx **ctx_id);
61 72
62u32 gss_svc_to_pseudoflavor(struct gss_api_mech *, u32 service); 73rpc_authflavor_t gss_svc_to_pseudoflavor(struct gss_api_mech *, u32 qop,
74 u32 service);
63u32 gss_pseudoflavor_to_service(struct gss_api_mech *, u32 pseudoflavor); 75u32 gss_pseudoflavor_to_service(struct gss_api_mech *, u32 pseudoflavor);
64char *gss_service_to_auth_domain_name(struct gss_api_mech *, u32 service); 76char *gss_service_to_auth_domain_name(struct gss_api_mech *, u32 service);
65 77
66struct pf_desc { 78struct pf_desc {
67 u32 pseudoflavor; 79 u32 pseudoflavor;
80 u32 qop;
68 u32 service; 81 u32 service;
69 char *name; 82 char *name;
70 char *auth_domain_name; 83 char *auth_domain_name;
@@ -77,7 +90,7 @@ struct pf_desc {
77struct gss_api_mech { 90struct gss_api_mech {
78 struct list_head gm_list; 91 struct list_head gm_list;
79 struct module *gm_owner; 92 struct module *gm_owner;
80 struct xdr_netobj gm_oid; 93 struct rpcsec_gss_oid gm_oid;
81 char *gm_name; 94 char *gm_name;
82 const struct gss_api_ops *gm_ops; 95 const struct gss_api_ops *gm_ops;
83 /* pseudoflavors supported by this mechanism: */ 96 /* pseudoflavors supported by this mechanism: */
@@ -121,7 +134,13 @@ void gss_mech_unregister(struct gss_api_mech *);
121 134
122/* returns a mechanism descriptor given an OID, and increments the mechanism's 135/* returns a mechanism descriptor given an OID, and increments the mechanism's
123 * reference count. */ 136 * reference count. */
124struct gss_api_mech * gss_mech_get_by_OID(struct xdr_netobj *); 137struct gss_api_mech * gss_mech_get_by_OID(struct rpcsec_gss_oid *);
138
139/* Given a GSS security tuple, look up a pseudoflavor */
140rpc_authflavor_t gss_mech_info2flavor(struct rpcsec_gss_info *);
141
142/* Given a pseudoflavor, look up a GSS security tuple */
143int gss_mech_flavor2info(rpc_authflavor_t, struct rpcsec_gss_info *);
125 144
126/* Returns a reference to a mechanism, given a name like "krb5" etc. */ 145/* Returns a reference to a mechanism, given a name like "krb5" etc. */
127struct gss_api_mech *gss_mech_get_by_name(const char *); 146struct gss_api_mech *gss_mech_get_by_name(const char *);
@@ -132,9 +151,6 @@ struct gss_api_mech *gss_mech_get_by_pseudoflavor(u32);
132/* Fill in an array with a list of supported pseudoflavors */ 151/* Fill in an array with a list of supported pseudoflavors */
133int gss_mech_list_pseudoflavors(rpc_authflavor_t *, int); 152int gss_mech_list_pseudoflavors(rpc_authflavor_t *, int);
134 153
135/* Just increments the mechanism's reference count and returns its input: */
136struct gss_api_mech * gss_mech_get(struct gss_api_mech *);
137
138/* For every successful gss_mech_get or gss_mech_get_by_* call there must be a 154/* For every successful gss_mech_get or gss_mech_get_by_* call there must be a
139 * corresponding call to gss_mech_put. */ 155 * corresponding call to gss_mech_put. */
140void gss_mech_put(struct gss_api_mech *); 156void gss_mech_put(struct gss_api_mech *);
diff --git a/net/sunrpc/Kconfig b/net/sunrpc/Kconfig
index 262caf03bd5f..241b54f30204 100644
--- a/net/sunrpc/Kconfig
+++ b/net/sunrpc/Kconfig
@@ -3,6 +3,7 @@ config SUNRPC
3 3
4config SUNRPC_GSS 4config SUNRPC_GSS
5 tristate 5 tristate
6 select OID_REGISTRY
6 7
7config SUNRPC_BACKCHANNEL 8config SUNRPC_BACKCHANNEL
8 bool 9 bool
diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c
index f5294047df77..ed2fdd210c0b 100644
--- a/net/sunrpc/auth.c
+++ b/net/sunrpc/auth.c
@@ -82,7 +82,7 @@ MODULE_PARM_DESC(auth_hashtable_size, "RPC credential cache hashtable size");
82 82
83static u32 83static u32
84pseudoflavor_to_flavor(u32 flavor) { 84pseudoflavor_to_flavor(u32 flavor) {
85 if (flavor >= RPC_AUTH_MAXFLAVOR) 85 if (flavor > RPC_AUTH_MAXFLAVOR)
86 return RPC_AUTH_GSS; 86 return RPC_AUTH_GSS;
87 return flavor; 87 return flavor;
88} 88}
@@ -124,6 +124,79 @@ rpcauth_unregister(const struct rpc_authops *ops)
124EXPORT_SYMBOL_GPL(rpcauth_unregister); 124EXPORT_SYMBOL_GPL(rpcauth_unregister);
125 125
126/** 126/**
127 * rpcauth_get_pseudoflavor - check if security flavor is supported
128 * @flavor: a security flavor
129 * @info: a GSS mech OID, quality of protection, and service value
130 *
131 * Verifies that an appropriate kernel module is available or already loaded.
132 * Returns an equivalent pseudoflavor, or RPC_AUTH_MAXFLAVOR if "flavor" is
133 * not supported locally.
134 */
135rpc_authflavor_t
136rpcauth_get_pseudoflavor(rpc_authflavor_t flavor, struct rpcsec_gss_info *info)
137{
138 const struct rpc_authops *ops;
139 rpc_authflavor_t pseudoflavor;
140
141 ops = auth_flavors[flavor];
142 if (ops == NULL)
143 request_module("rpc-auth-%u", flavor);
144 spin_lock(&rpc_authflavor_lock);
145 ops = auth_flavors[flavor];
146 if (ops == NULL || !try_module_get(ops->owner)) {
147 spin_unlock(&rpc_authflavor_lock);
148 return RPC_AUTH_MAXFLAVOR;
149 }
150 spin_unlock(&rpc_authflavor_lock);
151
152 pseudoflavor = flavor;
153 if (ops->info2flavor != NULL)
154 pseudoflavor = ops->info2flavor(info);
155
156 module_put(ops->owner);
157 return pseudoflavor;
158}
159EXPORT_SYMBOL_GPL(rpcauth_get_pseudoflavor);
160
161/**
162 * rpcauth_get_gssinfo - find GSS tuple matching a GSS pseudoflavor
163 * @pseudoflavor: GSS pseudoflavor to match
164 * @info: rpcsec_gss_info structure to fill in
165 *
166 * Returns zero and fills in "info" if pseudoflavor matches a
167 * supported mechanism.
168 */
169int
170rpcauth_get_gssinfo(rpc_authflavor_t pseudoflavor, struct rpcsec_gss_info *info)
171{
172 rpc_authflavor_t flavor = pseudoflavor_to_flavor(pseudoflavor);
173 const struct rpc_authops *ops;
174 int result;
175
176 if (flavor >= RPC_AUTH_MAXFLAVOR)
177 return -EINVAL;
178
179 ops = auth_flavors[flavor];
180 if (ops == NULL)
181 request_module("rpc-auth-%u", flavor);
182 spin_lock(&rpc_authflavor_lock);
183 ops = auth_flavors[flavor];
184 if (ops == NULL || !try_module_get(ops->owner)) {
185 spin_unlock(&rpc_authflavor_lock);
186 return -ENOENT;
187 }
188 spin_unlock(&rpc_authflavor_lock);
189
190 result = -ENOENT;
191 if (ops->flavor2info != NULL)
192 result = ops->flavor2info(pseudoflavor, info);
193
194 module_put(ops->owner);
195 return result;
196}
197EXPORT_SYMBOL_GPL(rpcauth_get_gssinfo);
198
199/**
127 * rpcauth_list_flavors - discover registered flavors and pseudoflavors 200 * rpcauth_list_flavors - discover registered flavors and pseudoflavors
128 * @array: array to fill in 201 * @array: array to fill in
129 * @size: size of "array" 202 * @size: size of "array"
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c
index 23563e783ec2..a764e227fdde 100644
--- a/net/sunrpc/auth_gss/auth_gss.c
+++ b/net/sunrpc/auth_gss/auth_gss.c
@@ -1641,6 +1641,8 @@ static const struct rpc_authops authgss_ops = {
1641 .pipes_create = gss_pipes_dentries_create, 1641 .pipes_create = gss_pipes_dentries_create,
1642 .pipes_destroy = gss_pipes_dentries_destroy, 1642 .pipes_destroy = gss_pipes_dentries_destroy,
1643 .list_pseudoflavors = gss_mech_list_pseudoflavors, 1643 .list_pseudoflavors = gss_mech_list_pseudoflavors,
1644 .info2flavor = gss_mech_info2flavor,
1645 .flavor2info = gss_mech_flavor2info,
1644}; 1646};
1645 1647
1646static const struct rpc_credops gss_credops = { 1648static const struct rpc_credops gss_credops = {
@@ -1733,6 +1735,7 @@ static void __exit exit_rpcsec_gss(void)
1733 rcu_barrier(); /* Wait for completion of call_rcu()'s */ 1735 rcu_barrier(); /* Wait for completion of call_rcu()'s */
1734} 1736}
1735 1737
1738MODULE_ALIAS("rpc-auth-6");
1736MODULE_LICENSE("GPL"); 1739MODULE_LICENSE("GPL");
1737module_param_named(expired_cred_retry_delay, 1740module_param_named(expired_cred_retry_delay,
1738 gss_expired_cred_retry_delay, 1741 gss_expired_cred_retry_delay,
diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c
index 3bc4a23938ea..0d3c158ef8fa 100644
--- a/net/sunrpc/auth_gss/gss_krb5_mech.c
+++ b/net/sunrpc/auth_gss/gss_krb5_mech.c
@@ -732,16 +732,19 @@ static const struct gss_api_ops gss_kerberos_ops = {
732static struct pf_desc gss_kerberos_pfs[] = { 732static struct pf_desc gss_kerberos_pfs[] = {
733 [0] = { 733 [0] = {
734 .pseudoflavor = RPC_AUTH_GSS_KRB5, 734 .pseudoflavor = RPC_AUTH_GSS_KRB5,
735 .qop = GSS_C_QOP_DEFAULT,
735 .service = RPC_GSS_SVC_NONE, 736 .service = RPC_GSS_SVC_NONE,
736 .name = "krb5", 737 .name = "krb5",
737 }, 738 },
738 [1] = { 739 [1] = {
739 .pseudoflavor = RPC_AUTH_GSS_KRB5I, 740 .pseudoflavor = RPC_AUTH_GSS_KRB5I,
741 .qop = GSS_C_QOP_DEFAULT,
740 .service = RPC_GSS_SVC_INTEGRITY, 742 .service = RPC_GSS_SVC_INTEGRITY,
741 .name = "krb5i", 743 .name = "krb5i",
742 }, 744 },
743 [2] = { 745 [2] = {
744 .pseudoflavor = RPC_AUTH_GSS_KRB5P, 746 .pseudoflavor = RPC_AUTH_GSS_KRB5P,
747 .qop = GSS_C_QOP_DEFAULT,
745 .service = RPC_GSS_SVC_PRIVACY, 748 .service = RPC_GSS_SVC_PRIVACY,
746 .name = "krb5p", 749 .name = "krb5p",
747 }, 750 },
@@ -753,11 +756,12 @@ MODULE_ALIAS("rpc-auth-gss-krb5p");
753MODULE_ALIAS("rpc-auth-gss-390003"); 756MODULE_ALIAS("rpc-auth-gss-390003");
754MODULE_ALIAS("rpc-auth-gss-390004"); 757MODULE_ALIAS("rpc-auth-gss-390004");
755MODULE_ALIAS("rpc-auth-gss-390005"); 758MODULE_ALIAS("rpc-auth-gss-390005");
759MODULE_ALIAS("rpc-auth-gss-1.2.840.113554.1.2.2");
756 760
757static struct gss_api_mech gss_kerberos_mech = { 761static struct gss_api_mech gss_kerberos_mech = {
758 .gm_name = "krb5", 762 .gm_name = "krb5",
759 .gm_owner = THIS_MODULE, 763 .gm_owner = THIS_MODULE,
760 .gm_oid = {9, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"}, 764 .gm_oid = { 9, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02" },
761 .gm_ops = &gss_kerberos_ops, 765 .gm_ops = &gss_kerberos_ops,
762 .gm_pf_num = ARRAY_SIZE(gss_kerberos_pfs), 766 .gm_pf_num = ARRAY_SIZE(gss_kerberos_pfs),
763 .gm_pfs = gss_kerberos_pfs, 767 .gm_pfs = gss_kerberos_pfs,
diff --git a/net/sunrpc/auth_gss/gss_mech_switch.c b/net/sunrpc/auth_gss/gss_mech_switch.c
index 43fd5bbf92c6..defa9d33925c 100644
--- a/net/sunrpc/auth_gss/gss_mech_switch.c
+++ b/net/sunrpc/auth_gss/gss_mech_switch.c
@@ -36,6 +36,7 @@
36#include <linux/types.h> 36#include <linux/types.h>
37#include <linux/slab.h> 37#include <linux/slab.h>
38#include <linux/module.h> 38#include <linux/module.h>
39#include <linux/oid_registry.h>
39#include <linux/sunrpc/msg_prot.h> 40#include <linux/sunrpc/msg_prot.h>
40#include <linux/sunrpc/gss_asn1.h> 41#include <linux/sunrpc/gss_asn1.h>
41#include <linux/sunrpc/auth_gss.h> 42#include <linux/sunrpc/auth_gss.h>
@@ -102,8 +103,13 @@ out:
102 return status; 103 return status;
103} 104}
104 105
105int 106/**
106gss_mech_register(struct gss_api_mech *gm) 107 * gss_mech_register - register a GSS mechanism
108 * @gm: GSS mechanism handle
109 *
110 * Returns zero if successful, or a negative errno.
111 */
112int gss_mech_register(struct gss_api_mech *gm)
107{ 113{
108 int status; 114 int status;
109 115
@@ -116,11 +122,14 @@ gss_mech_register(struct gss_api_mech *gm)
116 dprintk("RPC: registered gss mechanism %s\n", gm->gm_name); 122 dprintk("RPC: registered gss mechanism %s\n", gm->gm_name);
117 return 0; 123 return 0;
118} 124}
119
120EXPORT_SYMBOL_GPL(gss_mech_register); 125EXPORT_SYMBOL_GPL(gss_mech_register);
121 126
122void 127/**
123gss_mech_unregister(struct gss_api_mech *gm) 128 * gss_mech_unregister - release a GSS mechanism
129 * @gm: GSS mechanism handle
130 *
131 */
132void gss_mech_unregister(struct gss_api_mech *gm)
124{ 133{
125 spin_lock(&registered_mechs_lock); 134 spin_lock(&registered_mechs_lock);
126 list_del(&gm->gm_list); 135 list_del(&gm->gm_list);
@@ -128,18 +137,14 @@ gss_mech_unregister(struct gss_api_mech *gm)
128 dprintk("RPC: unregistered gss mechanism %s\n", gm->gm_name); 137 dprintk("RPC: unregistered gss mechanism %s\n", gm->gm_name);
129 gss_mech_free(gm); 138 gss_mech_free(gm);
130} 139}
131
132EXPORT_SYMBOL_GPL(gss_mech_unregister); 140EXPORT_SYMBOL_GPL(gss_mech_unregister);
133 141
134struct gss_api_mech * 142static struct gss_api_mech *gss_mech_get(struct gss_api_mech *gm)
135gss_mech_get(struct gss_api_mech *gm)
136{ 143{
137 __module_get(gm->gm_owner); 144 __module_get(gm->gm_owner);
138 return gm; 145 return gm;
139} 146}
140 147
141EXPORT_SYMBOL_GPL(gss_mech_get);
142
143static struct gss_api_mech * 148static struct gss_api_mech *
144_gss_mech_get_by_name(const char *name) 149_gss_mech_get_by_name(const char *name)
145{ 150{
@@ -169,12 +174,16 @@ struct gss_api_mech * gss_mech_get_by_name(const char *name)
169 } 174 }
170 return gm; 175 return gm;
171} 176}
172EXPORT_SYMBOL_GPL(gss_mech_get_by_name);
173 177
174struct gss_api_mech * 178struct gss_api_mech *gss_mech_get_by_OID(struct rpcsec_gss_oid *obj)
175gss_mech_get_by_OID(struct xdr_netobj *obj)
176{ 179{
177 struct gss_api_mech *pos, *gm = NULL; 180 struct gss_api_mech *pos, *gm = NULL;
181 char buf[32];
182
183 if (sprint_oid(obj->data, obj->len, buf, sizeof(buf)) < 0)
184 return NULL;
185 dprintk("RPC: %s(%s)\n", __func__, buf);
186 request_module("rpc-auth-gss-%s", buf);
178 187
179 spin_lock(&registered_mechs_lock); 188 spin_lock(&registered_mechs_lock);
180 list_for_each_entry(pos, &registered_mechs, gm_list) { 189 list_for_each_entry(pos, &registered_mechs, gm_list) {
@@ -188,11 +197,8 @@ gss_mech_get_by_OID(struct xdr_netobj *obj)
188 } 197 }
189 spin_unlock(&registered_mechs_lock); 198 spin_unlock(&registered_mechs_lock);
190 return gm; 199 return gm;
191
192} 200}
193 201
194EXPORT_SYMBOL_GPL(gss_mech_get_by_OID);
195
196static inline int 202static inline int
197mech_supports_pseudoflavor(struct gss_api_mech *gm, u32 pseudoflavor) 203mech_supports_pseudoflavor(struct gss_api_mech *gm, u32 pseudoflavor)
198{ 204{
@@ -237,8 +243,6 @@ gss_mech_get_by_pseudoflavor(u32 pseudoflavor)
237 return gm; 243 return gm;
238} 244}
239 245
240EXPORT_SYMBOL_GPL(gss_mech_get_by_pseudoflavor);
241
242/** 246/**
243 * gss_mech_list_pseudoflavors - Discover registered GSS pseudoflavors 247 * gss_mech_list_pseudoflavors - Discover registered GSS pseudoflavors
244 * @array: array to fill in 248 * @array: array to fill in
@@ -268,19 +272,82 @@ int gss_mech_list_pseudoflavors(rpc_authflavor_t *array_ptr, int size)
268 return i; 272 return i;
269} 273}
270 274
271u32 275/**
272gss_svc_to_pseudoflavor(struct gss_api_mech *gm, u32 service) 276 * gss_svc_to_pseudoflavor - map a GSS service number to a pseudoflavor
277 * @gm: GSS mechanism handle
278 * @qop: GSS quality-of-protection value
279 * @service: GSS service value
280 *
281 * Returns a matching security flavor, or RPC_AUTH_MAXFLAVOR if none is found.
282 */
283rpc_authflavor_t gss_svc_to_pseudoflavor(struct gss_api_mech *gm, u32 qop,
284 u32 service)
273{ 285{
274 int i; 286 int i;
275 287
276 for (i = 0; i < gm->gm_pf_num; i++) { 288 for (i = 0; i < gm->gm_pf_num; i++) {
277 if (gm->gm_pfs[i].service == service) { 289 if (gm->gm_pfs[i].qop == qop &&
290 gm->gm_pfs[i].service == service) {
278 return gm->gm_pfs[i].pseudoflavor; 291 return gm->gm_pfs[i].pseudoflavor;
279 } 292 }
280 } 293 }
281 return RPC_AUTH_MAXFLAVOR; /* illegal value */ 294 return RPC_AUTH_MAXFLAVOR;
295}
296
297/**
298 * gss_mech_info2flavor - look up a pseudoflavor given a GSS tuple
299 * @info: a GSS mech OID, quality of protection, and service value
300 *
301 * Returns a matching pseudoflavor, or RPC_AUTH_MAXFLAVOR if the tuple is
302 * not supported.
303 */
304rpc_authflavor_t gss_mech_info2flavor(struct rpcsec_gss_info *info)
305{
306 rpc_authflavor_t pseudoflavor;
307 struct gss_api_mech *gm;
308
309 gm = gss_mech_get_by_OID(&info->oid);
310 if (gm == NULL)
311 return RPC_AUTH_MAXFLAVOR;
312
313 pseudoflavor = gss_svc_to_pseudoflavor(gm, info->qop, info->service);
314
315 gss_mech_put(gm);
316 return pseudoflavor;
317}
318
319/**
320 * gss_mech_flavor2info - look up a GSS tuple for a given pseudoflavor
321 * @pseudoflavor: GSS pseudoflavor to match
322 * @info: rpcsec_gss_info structure to fill in
323 *
324 * Returns zero and fills in "info" if pseudoflavor matches a
325 * supported mechanism. Otherwise a negative errno is returned.
326 */
327int gss_mech_flavor2info(rpc_authflavor_t pseudoflavor,
328 struct rpcsec_gss_info *info)
329{
330 struct gss_api_mech *gm;
331 int i;
332
333 gm = gss_mech_get_by_pseudoflavor(pseudoflavor);
334 if (gm == NULL)
335 return -ENOENT;
336
337 for (i = 0; i < gm->gm_pf_num; i++) {
338 if (gm->gm_pfs[i].pseudoflavor == pseudoflavor) {
339 memcpy(info->oid.data, gm->gm_oid.data, gm->gm_oid.len);
340 info->oid.len = gm->gm_oid.len;
341 info->qop = gm->gm_pfs[i].qop;
342 info->service = gm->gm_pfs[i].service;
343 gss_mech_put(gm);
344 return 0;
345 }
346 }
347
348 gss_mech_put(gm);
349 return -ENOENT;
282} 350}
283EXPORT_SYMBOL_GPL(gss_svc_to_pseudoflavor);
284 351
285u32 352u32
286gss_pseudoflavor_to_service(struct gss_api_mech *gm, u32 pseudoflavor) 353gss_pseudoflavor_to_service(struct gss_api_mech *gm, u32 pseudoflavor)
@@ -294,8 +361,6 @@ gss_pseudoflavor_to_service(struct gss_api_mech *gm, u32 pseudoflavor)
294 return 0; 361 return 0;
295} 362}
296 363
297EXPORT_SYMBOL_GPL(gss_pseudoflavor_to_service);
298
299char * 364char *
300gss_service_to_auth_domain_name(struct gss_api_mech *gm, u32 service) 365gss_service_to_auth_domain_name(struct gss_api_mech *gm, u32 service)
301{ 366{
@@ -308,8 +373,6 @@ gss_service_to_auth_domain_name(struct gss_api_mech *gm, u32 service)
308 return NULL; 373 return NULL;
309} 374}
310 375
311EXPORT_SYMBOL_GPL(gss_service_to_auth_domain_name);
312
313void 376void
314gss_mech_put(struct gss_api_mech * gm) 377gss_mech_put(struct gss_api_mech * gm)
315{ 378{
@@ -317,8 +380,6 @@ gss_mech_put(struct gss_api_mech * gm)
317 module_put(gm->gm_owner); 380 module_put(gm->gm_owner);
318} 381}
319 382
320EXPORT_SYMBOL_GPL(gss_mech_put);
321
322/* The mech could probably be determined from the token instead, but it's just 383/* The mech could probably be determined from the token instead, but it's just
323 * as easy for now to pass it in. */ 384 * as easy for now to pass it in. */
324int 385int
diff --git a/net/sunrpc/auth_gss/gss_rpc_upcall.c b/net/sunrpc/auth_gss/gss_rpc_upcall.c
index 3f874d704859..c63273604ddc 100644
--- a/net/sunrpc/auth_gss/gss_rpc_upcall.c
+++ b/net/sunrpc/auth_gss/gss_rpc_upcall.c
@@ -220,7 +220,6 @@ static int gssp_call(struct net *net, struct rpc_message *msg)
220 220
221/* numbers somewhat arbitrary but large enough for current needs */ 221/* numbers somewhat arbitrary but large enough for current needs */
222#define GSSX_MAX_OUT_HANDLE 128 222#define GSSX_MAX_OUT_HANDLE 128
223#define GSSX_MAX_MECH_OID 16
224#define GSSX_MAX_SRC_PRINC 256 223#define GSSX_MAX_SRC_PRINC 256
225#define GSSX_KMEMBUF (GSSX_max_output_handle_sz + \ 224#define GSSX_KMEMBUF (GSSX_max_output_handle_sz + \
226 GSSX_max_oid_sz + \ 225 GSSX_max_oid_sz + \
@@ -242,7 +241,7 @@ int gssp_accept_sec_context_upcall(struct net *net,
242 * buffers but let the xdr code kmalloc them: 241 * buffers but let the xdr code kmalloc them:
243 */ 242 */
244 .exported_context_token.len = GSSX_max_output_handle_sz, 243 .exported_context_token.len = GSSX_max_output_handle_sz,
245 .mech.len = GSSX_max_oid_sz, 244 .mech.len = GSS_OID_MAX_LEN,
246 .src_name.display_name.len = GSSX_max_princ_sz 245 .src_name.display_name.len = GSSX_max_princ_sz
247 }; 246 };
248 struct gssx_res_accept_sec_context res = { 247 struct gssx_res_accept_sec_context res = {
@@ -272,7 +271,9 @@ int gssp_accept_sec_context_upcall(struct net *net,
272 data->minor_status = res.status.minor_status; 271 data->minor_status = res.status.minor_status;
273 if (res.context_handle) { 272 if (res.context_handle) {
274 data->out_handle = rctxh.exported_context_token; 273 data->out_handle = rctxh.exported_context_token;
275 data->mech_oid = rctxh.mech; 274 data->mech_oid.len = rctxh.mech.len;
275 memcpy(data->mech_oid.data, rctxh.mech.data,
276 data->mech_oid.len);
276 client_name = rctxh.src_name.display_name; 277 client_name = rctxh.src_name.display_name;
277 } 278 }
278 279
diff --git a/net/sunrpc/auth_gss/gss_rpc_upcall.h b/net/sunrpc/auth_gss/gss_rpc_upcall.h
index 4c2caaa7e84e..1e542aded90a 100644
--- a/net/sunrpc/auth_gss/gss_rpc_upcall.h
+++ b/net/sunrpc/auth_gss/gss_rpc_upcall.h
@@ -21,6 +21,7 @@
21#ifndef _GSS_RPC_UPCALL_H 21#ifndef _GSS_RPC_UPCALL_H
22#define _GSS_RPC_UPCALL_H 22#define _GSS_RPC_UPCALL_H
23 23
24#include <linux/sunrpc/gss_api.h>
24#include <linux/sunrpc/auth_gss.h> 25#include <linux/sunrpc/auth_gss.h>
25#include "gss_rpc_xdr.h" 26#include "gss_rpc_xdr.h"
26#include "../netns.h" 27#include "../netns.h"
@@ -30,7 +31,7 @@ struct gssp_upcall_data {
30 struct gssp_in_token in_token; 31 struct gssp_in_token in_token;
31 struct xdr_netobj out_handle; 32 struct xdr_netobj out_handle;
32 struct xdr_netobj out_token; 33 struct xdr_netobj out_token;
33 struct xdr_netobj mech_oid; 34 struct rpcsec_gss_oid mech_oid;
34 struct svc_cred creds; 35 struct svc_cred creds;
35 int found_creds; 36 int found_creds;
36 int major_status; 37 int major_status;
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c
index 58f5bc329408..1c66a3b78329 100644
--- a/net/sunrpc/auth_gss/svcauth_gss.c
+++ b/net/sunrpc/auth_gss/svcauth_gss.c
@@ -1544,7 +1544,9 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
1544 svcdata->rsci = rsci; 1544 svcdata->rsci = rsci;
1545 cache_get(&rsci->h); 1545 cache_get(&rsci->h);
1546 rqstp->rq_cred.cr_flavor = gss_svc_to_pseudoflavor( 1546 rqstp->rq_cred.cr_flavor = gss_svc_to_pseudoflavor(
1547 rsci->mechctx->mech_type, gc->gc_svc); 1547 rsci->mechctx->mech_type,
1548 GSS_C_QOP_DEFAULT,
1549 gc->gc_svc);
1548 ret = SVC_OK; 1550 ret = SVC_OK;
1549 goto out; 1551 goto out;
1550 } 1552 }
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index ac74399e8899..3f7930f938cc 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -304,10 +304,8 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru
304 err = rpciod_up(); 304 err = rpciod_up();
305 if (err) 305 if (err)
306 goto out_no_rpciod; 306 goto out_no_rpciod;
307 err = -EINVAL;
308 if (!xprt)
309 goto out_no_xprt;
310 307
308 err = -EINVAL;
311 if (args->version >= program->nrvers) 309 if (args->version >= program->nrvers)
312 goto out_err; 310 goto out_err;
313 version = program->version[args->version]; 311 version = program->version[args->version];
@@ -382,10 +380,9 @@ out_no_principal:
382out_no_stats: 380out_no_stats:
383 kfree(clnt); 381 kfree(clnt);
384out_err: 382out_err:
385 xprt_put(xprt);
386out_no_xprt:
387 rpciod_down(); 383 rpciod_down();
388out_no_rpciod: 384out_no_rpciod:
385 xprt_put(xprt);
389 return ERR_PTR(err); 386 return ERR_PTR(err);
390} 387}
391 388
@@ -516,7 +513,7 @@ static struct rpc_clnt *__rpc_clone_client(struct rpc_create_args *args,
516 new = rpc_new_client(args, xprt); 513 new = rpc_new_client(args, xprt);
517 if (IS_ERR(new)) { 514 if (IS_ERR(new)) {
518 err = PTR_ERR(new); 515 err = PTR_ERR(new);
519 goto out_put; 516 goto out_err;
520 } 517 }
521 518
522 atomic_inc(&clnt->cl_count); 519 atomic_inc(&clnt->cl_count);
@@ -529,8 +526,6 @@ static struct rpc_clnt *__rpc_clone_client(struct rpc_create_args *args,
529 new->cl_chatty = clnt->cl_chatty; 526 new->cl_chatty = clnt->cl_chatty;
530 return new; 527 return new;
531 528
532out_put:
533 xprt_put(xprt);
534out_err: 529out_err:
535 dprintk("RPC: %s: returned error %d\n", __func__, err); 530 dprintk("RPC: %s: returned error %d\n", __func__, err);
536 return ERR_PTR(err); 531 return ERR_PTR(err);