diff options
author | J. Bruce Fields <bfields@redhat.com> | 2013-04-29 14:03:30 -0400 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2013-04-29 16:23:34 -0400 |
commit | b1df7637232927ac69ed1a32e9c6b768f635b7d4 (patch) | |
tree | cf5fdd96cccb3a89f4e0dea895775eb7c428c533 | |
parent | dd30333cf5a2f9dfecda5c6f4523133f13847aae (diff) | |
parent | 721ccfb79b6f74f4052de70236d24047e73682d4 (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.c | 49 | ||||
-rw-r--r-- | fs/nfs/nfs4namespace.c | 43 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 136 | ||||
-rw-r--r-- | fs/nfs/nfs4state.c | 68 | ||||
-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 | ||||
-rw-r--r-- | include/linux/nfs_xdr.h | 24 | ||||
-rw-r--r-- | include/linux/sunrpc/auth.h | 9 | ||||
-rw-r--r-- | include/linux/sunrpc/gss_api.h | 30 | ||||
-rw-r--r-- | net/sunrpc/Kconfig | 1 | ||||
-rw-r--r-- | net/sunrpc/auth.c | 75 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/auth_gss.c | 3 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/gss_krb5_mech.c | 6 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/gss_mech_switch.c | 119 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/gss_rpc_upcall.c | 7 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/gss_rpc_upcall.h | 3 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/svcauth_gss.c | 4 | ||||
-rw-r--r-- | net/sunrpc/clnt.c | 11 |
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 | */ | ||
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 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 | */ | ||
2547 | static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle, | 2580 | static 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 | /* | 2613 | static 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 | */ |
2583 | int nfs4_proc_get_rootfh(struct nfs_server *server, struct nfs_fh *fhandle, | 2628 | int 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, | |||
3473 | static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo) | 3518 | static 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 | ||
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,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 | ||
1953 | out_unlock: | 1924 | out_unlock: |
1954 | mutex_unlock(&nfs_clid_init_mutex); | 1925 | mutex_unlock(&nfs_clid_init_mutex); |
1955 | out_free: | ||
1956 | kfree(flavors); | ||
1957 | out: | ||
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 | ||
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 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 | */ |
1616 | static int nfs_walk_authlist(struct nfs_parsed_mount_data *args, | 1614 | static 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"); | 1656 | out_default: |
1652 | nfs_umount(request); | 1657 | flavor = RPC_AUTH_UNIX; |
1653 | return -EACCES; | 1658 | out_set: |
1659 | args->auth_flavors[0] = flavor; | ||
1660 | out: | ||
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 | ||
1724 | struct dentry *nfs_try_mount(int flags, const char *dev_name, | 1728 | struct 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 | ||
3084 | static __be32 | 3084 | static __be32 |
3085 | nfsd4_do_encode_secinfo(struct nfsd4_compoundres *resp, | 3085 | nfsd4_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 | |||
3144 | out: | 3142 | out: |
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 */ | ||
18 | struct nfs4_secinfo_flavors; | ||
19 | |||
20 | struct nfs4_string { | 17 | struct 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 | ||
1056 | struct nfs4_secinfo_oid { | 1053 | struct 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 | |||
1061 | struct nfs4_secinfo_gss { | ||
1062 | struct nfs4_secinfo_oid sec_oid4; | ||
1063 | unsigned int qop4; | ||
1064 | unsigned int service; | ||
1065 | }; | ||
1066 | |||
1067 | struct nfs4_secinfo_flavor { | ||
1068 | unsigned int flavor; | ||
1069 | struct nfs4_secinfo_gss gss; | ||
1070 | }; | 1056 | }; |
1071 | 1057 | ||
1072 | struct nfs4_secinfo_flavors { | 1058 | struct 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 | ||
1077 | struct nfs4_secinfo_arg { | 1063 | struct 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 | ||
25 | struct rpcsec_gss_info; | ||
26 | |||
25 | /* Work around the lack of a VFS credential */ | 27 | /* Work around the lack of a VFS credential */ |
26 | struct auth_cred { | 28 | struct 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 | ||
108 | struct rpc_credops { | 113 | struct rpc_credops { |
@@ -137,6 +142,10 @@ int rpcauth_register(const struct rpc_authops *); | |||
137 | int rpcauth_unregister(const struct rpc_authops *); | 142 | int rpcauth_unregister(const struct rpc_authops *); |
138 | struct rpc_auth * rpcauth_create(rpc_authflavor_t, struct rpc_clnt *); | 143 | struct rpc_auth * rpcauth_create(rpc_authflavor_t, struct rpc_clnt *); |
139 | void rpcauth_release(struct rpc_auth *); | 144 | void rpcauth_release(struct rpc_auth *); |
145 | rpc_authflavor_t rpcauth_get_pseudoflavor(rpc_authflavor_t, | ||
146 | struct rpcsec_gss_info *); | ||
147 | int rpcauth_get_gssinfo(rpc_authflavor_t, | ||
148 | struct rpcsec_gss_info *); | ||
140 | int rpcauth_list_flavors(rpc_authflavor_t *, int); | 149 | int rpcauth_list_flavors(rpc_authflavor_t *, int); |
141 | struct rpc_cred * rpcauth_lookup_credcache(struct rpc_auth *, struct auth_cred *, int); | 150 | struct rpc_cred * rpcauth_lookup_credcache(struct rpc_auth *, struct auth_cred *, int); |
142 | void rpcauth_init_cred(struct rpc_cred *, const struct auth_cred *, struct rpc_auth *, const struct rpc_credops *); | 151 | void 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 |
32 | struct rpcsec_gss_oid { | ||
33 | unsigned int len; | ||
34 | u8 data[GSS_OID_MAX_LEN]; | ||
35 | }; | ||
36 | |||
37 | /* From RFC 3530 */ | ||
38 | struct 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( | |||
59 | u32 gss_delete_sec_context( | 70 | u32 gss_delete_sec_context( |
60 | struct gss_ctx **ctx_id); | 71 | struct gss_ctx **ctx_id); |
61 | 72 | ||
62 | u32 gss_svc_to_pseudoflavor(struct gss_api_mech *, u32 service); | 73 | rpc_authflavor_t gss_svc_to_pseudoflavor(struct gss_api_mech *, u32 qop, |
74 | u32 service); | ||
63 | u32 gss_pseudoflavor_to_service(struct gss_api_mech *, u32 pseudoflavor); | 75 | u32 gss_pseudoflavor_to_service(struct gss_api_mech *, u32 pseudoflavor); |
64 | char *gss_service_to_auth_domain_name(struct gss_api_mech *, u32 service); | 76 | char *gss_service_to_auth_domain_name(struct gss_api_mech *, u32 service); |
65 | 77 | ||
66 | struct pf_desc { | 78 | struct 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 { | |||
77 | struct gss_api_mech { | 90 | struct 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. */ |
124 | struct gss_api_mech * gss_mech_get_by_OID(struct xdr_netobj *); | 137 | struct gss_api_mech * gss_mech_get_by_OID(struct rpcsec_gss_oid *); |
138 | |||
139 | /* Given a GSS security tuple, look up a pseudoflavor */ | ||
140 | rpc_authflavor_t gss_mech_info2flavor(struct rpcsec_gss_info *); | ||
141 | |||
142 | /* Given a pseudoflavor, look up a GSS security tuple */ | ||
143 | int 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. */ |
127 | struct gss_api_mech *gss_mech_get_by_name(const char *); | 146 | struct 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 */ |
133 | int gss_mech_list_pseudoflavors(rpc_authflavor_t *, int); | 152 | int gss_mech_list_pseudoflavors(rpc_authflavor_t *, int); |
134 | 153 | ||
135 | /* Just increments the mechanism's reference count and returns its input: */ | ||
136 | struct 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. */ |
140 | void gss_mech_put(struct gss_api_mech *); | 156 | void 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 | ||
4 | config SUNRPC_GSS | 4 | config SUNRPC_GSS |
5 | tristate | 5 | tristate |
6 | select OID_REGISTRY | ||
6 | 7 | ||
7 | config SUNRPC_BACKCHANNEL | 8 | config 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 | ||
83 | static u32 | 83 | static u32 |
84 | pseudoflavor_to_flavor(u32 flavor) { | 84 | pseudoflavor_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) | |||
124 | EXPORT_SYMBOL_GPL(rpcauth_unregister); | 124 | EXPORT_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 | */ | ||
135 | rpc_authflavor_t | ||
136 | rpcauth_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 | } | ||
159 | EXPORT_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 | */ | ||
169 | int | ||
170 | rpcauth_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 | } | ||
197 | EXPORT_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 | ||
1646 | static const struct rpc_credops gss_credops = { | 1648 | static 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 | ||
1738 | MODULE_ALIAS("rpc-auth-6"); | ||
1736 | MODULE_LICENSE("GPL"); | 1739 | MODULE_LICENSE("GPL"); |
1737 | module_param_named(expired_cred_retry_delay, | 1740 | module_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 = { | |||
732 | static struct pf_desc gss_kerberos_pfs[] = { | 732 | static 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"); | |||
753 | MODULE_ALIAS("rpc-auth-gss-390003"); | 756 | MODULE_ALIAS("rpc-auth-gss-390003"); |
754 | MODULE_ALIAS("rpc-auth-gss-390004"); | 757 | MODULE_ALIAS("rpc-auth-gss-390004"); |
755 | MODULE_ALIAS("rpc-auth-gss-390005"); | 758 | MODULE_ALIAS("rpc-auth-gss-390005"); |
759 | MODULE_ALIAS("rpc-auth-gss-1.2.840.113554.1.2.2"); | ||
756 | 760 | ||
757 | static struct gss_api_mech gss_kerberos_mech = { | 761 | static 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 | ||
105 | int | 106 | /** |
106 | gss_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 | */ | ||
112 | int 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 | |||
120 | EXPORT_SYMBOL_GPL(gss_mech_register); | 125 | EXPORT_SYMBOL_GPL(gss_mech_register); |
121 | 126 | ||
122 | void | 127 | /** |
123 | gss_mech_unregister(struct gss_api_mech *gm) | 128 | * gss_mech_unregister - release a GSS mechanism |
129 | * @gm: GSS mechanism handle | ||
130 | * | ||
131 | */ | ||
132 | void gss_mech_unregister(struct gss_api_mech *gm) | ||
124 | { | 133 | { |
125 | spin_lock(®istered_mechs_lock); | 134 | spin_lock(®istered_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 | |||
132 | EXPORT_SYMBOL_GPL(gss_mech_unregister); | 140 | EXPORT_SYMBOL_GPL(gss_mech_unregister); |
133 | 141 | ||
134 | struct gss_api_mech * | 142 | static struct gss_api_mech *gss_mech_get(struct gss_api_mech *gm) |
135 | gss_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 | ||
141 | EXPORT_SYMBOL_GPL(gss_mech_get); | ||
142 | |||
143 | static struct gss_api_mech * | 148 | static 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 | } |
172 | EXPORT_SYMBOL_GPL(gss_mech_get_by_name); | ||
173 | 177 | ||
174 | struct gss_api_mech * | 178 | struct gss_api_mech *gss_mech_get_by_OID(struct rpcsec_gss_oid *obj) |
175 | gss_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(®istered_mechs_lock); | 188 | spin_lock(®istered_mechs_lock); |
180 | list_for_each_entry(pos, ®istered_mechs, gm_list) { | 189 | list_for_each_entry(pos, ®istered_mechs, gm_list) { |
@@ -188,11 +197,8 @@ gss_mech_get_by_OID(struct xdr_netobj *obj) | |||
188 | } | 197 | } |
189 | spin_unlock(®istered_mechs_lock); | 198 | spin_unlock(®istered_mechs_lock); |
190 | return gm; | 199 | return gm; |
191 | |||
192 | } | 200 | } |
193 | 201 | ||
194 | EXPORT_SYMBOL_GPL(gss_mech_get_by_OID); | ||
195 | |||
196 | static inline int | 202 | static inline int |
197 | mech_supports_pseudoflavor(struct gss_api_mech *gm, u32 pseudoflavor) | 203 | mech_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 | ||
240 | EXPORT_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 | ||
271 | u32 | 275 | /** |
272 | gss_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 | */ | ||
283 | rpc_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 | */ | ||
304 | rpc_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 | */ | ||
327 | int 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 | } |
283 | EXPORT_SYMBOL_GPL(gss_svc_to_pseudoflavor); | ||
284 | 351 | ||
285 | u32 | 352 | u32 |
286 | gss_pseudoflavor_to_service(struct gss_api_mech *gm, u32 pseudoflavor) | 353 | gss_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 | ||
297 | EXPORT_SYMBOL_GPL(gss_pseudoflavor_to_service); | ||
298 | |||
299 | char * | 364 | char * |
300 | gss_service_to_auth_domain_name(struct gss_api_mech *gm, u32 service) | 365 | gss_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 | ||
311 | EXPORT_SYMBOL_GPL(gss_service_to_auth_domain_name); | ||
312 | |||
313 | void | 376 | void |
314 | gss_mech_put(struct gss_api_mech * gm) | 377 | gss_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 | ||
320 | EXPORT_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. */ |
324 | int | 385 | int |
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: | |||
382 | out_no_stats: | 380 | out_no_stats: |
383 | kfree(clnt); | 381 | kfree(clnt); |
384 | out_err: | 382 | out_err: |
385 | xprt_put(xprt); | ||
386 | out_no_xprt: | ||
387 | rpciod_down(); | 383 | rpciod_down(); |
388 | out_no_rpciod: | 384 | out_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 | ||
532 | out_put: | ||
533 | xprt_put(xprt); | ||
534 | out_err: | 529 | out_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); |