diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-24 14:46:16 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-24 14:46:16 -0400 |
commit | 563307b2fa15d687abc54bd980b9847ebf0e3231 (patch) | |
tree | 7f16be30217a2e66360ede97aa27d07a4ebd7e55 /net/sunrpc/auth_gss | |
parent | 10c993a6b5418cb1026775765ba4c70ffb70853d (diff) | |
parent | 233607dbbc823caf685e778cabc49fb7f679900b (diff) |
Merge git://git.linux-nfs.org/projects/trondmy/nfs-2.6
* git://git.linux-nfs.org/projects/trondmy/nfs-2.6: (80 commits)
SUNRPC: Invalidate the RPCSEC_GSS session if the server dropped the request
make nfs_automount_list static
NFS: remove duplicate flags assignment from nfs_validate_mount_data
NFS - fix potential NULL pointer dereference v2
SUNRPC: Don't change the RPCSEC_GSS context on a credential that is in use
SUNRPC: Fix a race in gss_refresh_upcall()
SUNRPC: Don't disconnect more than once if retransmitting NFSv4 requests
SUNRPC: Remove the unused export of xprt_force_disconnect
SUNRPC: remove XS_SENDMSG_RETRY
SUNRPC: Protect creds against early garbage collection
NFSv4: Attempt to use machine credentials in SETCLIENTID calls
NFSv4: Reintroduce machine creds
NFSv4: Don't use cred->cr_ops->cr_name in nfs4_proc_setclientid()
nfs: fix printout of multiword bitfields
nfs: return negative error value from nfs{,4}_stat_to_errno
NLM/lockd: Ensure client locking calls use correct credentials
NFS: Remove the buggy lock-if-signalled case from do_setlk()
NLM/lockd: Fix a race when cancelling a blocking lock
NLM/lockd: Ensure that nlmclnt_cancel() returns results of the CANCEL call
NLM: Remove the signal masking in nlmclnt_proc/nlmclnt_cancel
...
Diffstat (limited to 'net/sunrpc/auth_gss')
-rw-r--r-- | net/sunrpc/auth_gss/auth_gss.c | 105 |
1 files changed, 68 insertions, 37 deletions
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 5828e5c060ca..cc12d5f5d5da 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c | |||
@@ -114,27 +114,14 @@ static void | |||
114 | gss_cred_set_ctx(struct rpc_cred *cred, struct gss_cl_ctx *ctx) | 114 | gss_cred_set_ctx(struct rpc_cred *cred, struct gss_cl_ctx *ctx) |
115 | { | 115 | { |
116 | struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); | 116 | struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); |
117 | struct gss_cl_ctx *old; | ||
118 | 117 | ||
119 | old = gss_cred->gc_ctx; | 118 | if (!test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags)) |
119 | return; | ||
120 | gss_get_ctx(ctx); | ||
120 | rcu_assign_pointer(gss_cred->gc_ctx, ctx); | 121 | rcu_assign_pointer(gss_cred->gc_ctx, ctx); |
121 | set_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); | 122 | set_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); |
123 | smp_mb__before_clear_bit(); | ||
122 | clear_bit(RPCAUTH_CRED_NEW, &cred->cr_flags); | 124 | clear_bit(RPCAUTH_CRED_NEW, &cred->cr_flags); |
123 | if (old) | ||
124 | gss_put_ctx(old); | ||
125 | } | ||
126 | |||
127 | static int | ||
128 | gss_cred_is_uptodate_ctx(struct rpc_cred *cred) | ||
129 | { | ||
130 | struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); | ||
131 | int res = 0; | ||
132 | |||
133 | rcu_read_lock(); | ||
134 | if (test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) && gss_cred->gc_ctx) | ||
135 | res = 1; | ||
136 | rcu_read_unlock(); | ||
137 | return res; | ||
138 | } | 125 | } |
139 | 126 | ||
140 | static const void * | 127 | static const void * |
@@ -266,6 +253,7 @@ gss_release_msg(struct gss_upcall_msg *gss_msg) | |||
266 | BUG_ON(!list_empty(&gss_msg->list)); | 253 | BUG_ON(!list_empty(&gss_msg->list)); |
267 | if (gss_msg->ctx != NULL) | 254 | if (gss_msg->ctx != NULL) |
268 | gss_put_ctx(gss_msg->ctx); | 255 | gss_put_ctx(gss_msg->ctx); |
256 | rpc_destroy_wait_queue(&gss_msg->rpc_waitqueue); | ||
269 | kfree(gss_msg); | 257 | kfree(gss_msg); |
270 | } | 258 | } |
271 | 259 | ||
@@ -339,7 +327,7 @@ gss_upcall_callback(struct rpc_task *task) | |||
339 | 327 | ||
340 | spin_lock(&inode->i_lock); | 328 | spin_lock(&inode->i_lock); |
341 | if (gss_msg->ctx) | 329 | if (gss_msg->ctx) |
342 | gss_cred_set_ctx(task->tk_msg.rpc_cred, gss_get_ctx(gss_msg->ctx)); | 330 | gss_cred_set_ctx(task->tk_msg.rpc_cred, gss_msg->ctx); |
343 | else | 331 | else |
344 | task->tk_status = gss_msg->msg.errno; | 332 | task->tk_status = gss_msg->msg.errno; |
345 | gss_cred->gc_upcall = NULL; | 333 | gss_cred->gc_upcall = NULL; |
@@ -370,9 +358,16 @@ gss_alloc_msg(struct gss_auth *gss_auth, uid_t uid) | |||
370 | static struct gss_upcall_msg * | 358 | static struct gss_upcall_msg * |
371 | gss_setup_upcall(struct rpc_clnt *clnt, struct gss_auth *gss_auth, struct rpc_cred *cred) | 359 | gss_setup_upcall(struct rpc_clnt *clnt, struct gss_auth *gss_auth, struct rpc_cred *cred) |
372 | { | 360 | { |
361 | struct gss_cred *gss_cred = container_of(cred, | ||
362 | struct gss_cred, gc_base); | ||
373 | struct gss_upcall_msg *gss_new, *gss_msg; | 363 | struct gss_upcall_msg *gss_new, *gss_msg; |
364 | uid_t uid = cred->cr_uid; | ||
374 | 365 | ||
375 | gss_new = gss_alloc_msg(gss_auth, cred->cr_uid); | 366 | /* Special case: rpc.gssd assumes that uid == 0 implies machine creds */ |
367 | if (gss_cred->gc_machine_cred != 0) | ||
368 | uid = 0; | ||
369 | |||
370 | gss_new = gss_alloc_msg(gss_auth, uid); | ||
376 | if (gss_new == NULL) | 371 | if (gss_new == NULL) |
377 | return ERR_PTR(-ENOMEM); | 372 | return ERR_PTR(-ENOMEM); |
378 | gss_msg = gss_add_msg(gss_auth, gss_new); | 373 | gss_msg = gss_add_msg(gss_auth, gss_new); |
@@ -408,13 +403,17 @@ gss_refresh_upcall(struct rpc_task *task) | |||
408 | } | 403 | } |
409 | spin_lock(&inode->i_lock); | 404 | spin_lock(&inode->i_lock); |
410 | if (gss_cred->gc_upcall != NULL) | 405 | if (gss_cred->gc_upcall != NULL) |
411 | rpc_sleep_on(&gss_cred->gc_upcall->rpc_waitqueue, task, NULL, NULL); | 406 | rpc_sleep_on(&gss_cred->gc_upcall->rpc_waitqueue, task, NULL); |
412 | else if (gss_msg->ctx == NULL && gss_msg->msg.errno >= 0) { | 407 | else if (gss_msg->ctx != NULL) { |
408 | gss_cred_set_ctx(task->tk_msg.rpc_cred, gss_msg->ctx); | ||
409 | gss_cred->gc_upcall = NULL; | ||
410 | rpc_wake_up_status(&gss_msg->rpc_waitqueue, gss_msg->msg.errno); | ||
411 | } else if (gss_msg->msg.errno >= 0) { | ||
413 | task->tk_timeout = 0; | 412 | task->tk_timeout = 0; |
414 | gss_cred->gc_upcall = gss_msg; | 413 | gss_cred->gc_upcall = gss_msg; |
415 | /* gss_upcall_callback will release the reference to gss_upcall_msg */ | 414 | /* gss_upcall_callback will release the reference to gss_upcall_msg */ |
416 | atomic_inc(&gss_msg->count); | 415 | atomic_inc(&gss_msg->count); |
417 | rpc_sleep_on(&gss_msg->rpc_waitqueue, task, gss_upcall_callback, NULL); | 416 | rpc_sleep_on(&gss_msg->rpc_waitqueue, task, gss_upcall_callback); |
418 | } else | 417 | } else |
419 | err = gss_msg->msg.errno; | 418 | err = gss_msg->msg.errno; |
420 | spin_unlock(&inode->i_lock); | 419 | spin_unlock(&inode->i_lock); |
@@ -454,7 +453,7 @@ gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred) | |||
454 | schedule(); | 453 | schedule(); |
455 | } | 454 | } |
456 | if (gss_msg->ctx) | 455 | if (gss_msg->ctx) |
457 | gss_cred_set_ctx(cred, gss_get_ctx(gss_msg->ctx)); | 456 | gss_cred_set_ctx(cred, gss_msg->ctx); |
458 | else | 457 | else |
459 | err = gss_msg->msg.errno; | 458 | err = gss_msg->msg.errno; |
460 | spin_unlock(&inode->i_lock); | 459 | spin_unlock(&inode->i_lock); |
@@ -709,7 +708,7 @@ gss_destroying_context(struct rpc_cred *cred) | |||
709 | struct rpc_task *task; | 708 | struct rpc_task *task; |
710 | 709 | ||
711 | if (gss_cred->gc_ctx == NULL || | 710 | if (gss_cred->gc_ctx == NULL || |
712 | gss_cred->gc_ctx->gc_proc == RPC_GSS_PROC_DESTROY) | 711 | test_and_clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) == 0) |
713 | return 0; | 712 | return 0; |
714 | 713 | ||
715 | gss_cred->gc_ctx->gc_proc = RPC_GSS_PROC_DESTROY; | 714 | gss_cred->gc_ctx->gc_proc = RPC_GSS_PROC_DESTROY; |
@@ -719,7 +718,7 @@ gss_destroying_context(struct rpc_cred *cred) | |||
719 | * by the RPC call or by the put_rpccred() below */ | 718 | * by the RPC call or by the put_rpccred() below */ |
720 | get_rpccred(cred); | 719 | get_rpccred(cred); |
721 | 720 | ||
722 | task = rpc_call_null(gss_auth->client, cred, RPC_TASK_ASYNC); | 721 | task = rpc_call_null(gss_auth->client, cred, RPC_TASK_ASYNC|RPC_TASK_SOFT); |
723 | if (!IS_ERR(task)) | 722 | if (!IS_ERR(task)) |
724 | rpc_put_task(task); | 723 | rpc_put_task(task); |
725 | 724 | ||
@@ -817,6 +816,7 @@ gss_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags) | |||
817 | */ | 816 | */ |
818 | cred->gc_base.cr_flags = 1UL << RPCAUTH_CRED_NEW; | 817 | cred->gc_base.cr_flags = 1UL << RPCAUTH_CRED_NEW; |
819 | cred->gc_service = gss_auth->service; | 818 | cred->gc_service = gss_auth->service; |
819 | cred->gc_machine_cred = acred->machine_cred; | ||
820 | kref_get(&gss_auth->kref); | 820 | kref_get(&gss_auth->kref); |
821 | return &cred->gc_base; | 821 | return &cred->gc_base; |
822 | 822 | ||
@@ -843,17 +843,16 @@ gss_match(struct auth_cred *acred, struct rpc_cred *rc, int flags) | |||
843 | { | 843 | { |
844 | struct gss_cred *gss_cred = container_of(rc, struct gss_cred, gc_base); | 844 | struct gss_cred *gss_cred = container_of(rc, struct gss_cred, gc_base); |
845 | 845 | ||
846 | /* | 846 | if (test_bit(RPCAUTH_CRED_NEW, &rc->cr_flags)) |
847 | * If the searchflags have set RPCAUTH_LOOKUP_NEW, then | ||
848 | * we don't really care if the credential has expired or not, | ||
849 | * since the caller should be prepared to reinitialise it. | ||
850 | */ | ||
851 | if ((flags & RPCAUTH_LOOKUP_NEW) && test_bit(RPCAUTH_CRED_NEW, &rc->cr_flags)) | ||
852 | goto out; | 847 | goto out; |
853 | /* Don't match with creds that have expired. */ | 848 | /* Don't match with creds that have expired. */ |
854 | if (gss_cred->gc_ctx && time_after(jiffies, gss_cred->gc_ctx->gc_expiry)) | 849 | if (time_after(jiffies, gss_cred->gc_ctx->gc_expiry)) |
850 | return 0; | ||
851 | if (!test_bit(RPCAUTH_CRED_UPTODATE, &rc->cr_flags)) | ||
855 | return 0; | 852 | return 0; |
856 | out: | 853 | out: |
854 | if (acred->machine_cred != gss_cred->gc_machine_cred) | ||
855 | return 0; | ||
857 | return (rc->cr_uid == acred->uid); | 856 | return (rc->cr_uid == acred->uid); |
858 | } | 857 | } |
859 | 858 | ||
@@ -917,16 +916,48 @@ out_put_ctx: | |||
917 | return NULL; | 916 | return NULL; |
918 | } | 917 | } |
919 | 918 | ||
919 | static int gss_renew_cred(struct rpc_task *task) | ||
920 | { | ||
921 | struct rpc_cred *oldcred = task->tk_msg.rpc_cred; | ||
922 | struct gss_cred *gss_cred = container_of(oldcred, | ||
923 | struct gss_cred, | ||
924 | gc_base); | ||
925 | struct rpc_auth *auth = oldcred->cr_auth; | ||
926 | struct auth_cred acred = { | ||
927 | .uid = oldcred->cr_uid, | ||
928 | .machine_cred = gss_cred->gc_machine_cred, | ||
929 | }; | ||
930 | struct rpc_cred *new; | ||
931 | |||
932 | new = gss_lookup_cred(auth, &acred, RPCAUTH_LOOKUP_NEW); | ||
933 | if (IS_ERR(new)) | ||
934 | return PTR_ERR(new); | ||
935 | task->tk_msg.rpc_cred = new; | ||
936 | put_rpccred(oldcred); | ||
937 | return 0; | ||
938 | } | ||
939 | |||
920 | /* | 940 | /* |
921 | * Refresh credentials. XXX - finish | 941 | * Refresh credentials. XXX - finish |
922 | */ | 942 | */ |
923 | static int | 943 | static int |
924 | gss_refresh(struct rpc_task *task) | 944 | gss_refresh(struct rpc_task *task) |
925 | { | 945 | { |
946 | struct rpc_cred *cred = task->tk_msg.rpc_cred; | ||
947 | int ret = 0; | ||
948 | |||
949 | if (!test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags) && | ||
950 | !test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags)) { | ||
951 | ret = gss_renew_cred(task); | ||
952 | if (ret < 0) | ||
953 | goto out; | ||
954 | cred = task->tk_msg.rpc_cred; | ||
955 | } | ||
926 | 956 | ||
927 | if (!gss_cred_is_uptodate_ctx(task->tk_msg.rpc_cred)) | 957 | if (test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags)) |
928 | return gss_refresh_upcall(task); | 958 | ret = gss_refresh_upcall(task); |
929 | return 0; | 959 | out: |
960 | return ret; | ||
930 | } | 961 | } |
931 | 962 | ||
932 | /* Dummy refresh routine: used only when destroying the context */ | 963 | /* Dummy refresh routine: used only when destroying the context */ |
@@ -1286,9 +1317,7 @@ out: | |||
1286 | static const struct rpc_authops authgss_ops = { | 1317 | static const struct rpc_authops authgss_ops = { |
1287 | .owner = THIS_MODULE, | 1318 | .owner = THIS_MODULE, |
1288 | .au_flavor = RPC_AUTH_GSS, | 1319 | .au_flavor = RPC_AUTH_GSS, |
1289 | #ifdef RPC_DEBUG | ||
1290 | .au_name = "RPCSEC_GSS", | 1320 | .au_name = "RPCSEC_GSS", |
1291 | #endif | ||
1292 | .create = gss_create, | 1321 | .create = gss_create, |
1293 | .destroy = gss_destroy, | 1322 | .destroy = gss_destroy, |
1294 | .lookup_cred = gss_lookup_cred, | 1323 | .lookup_cred = gss_lookup_cred, |
@@ -1299,6 +1328,7 @@ static const struct rpc_credops gss_credops = { | |||
1299 | .cr_name = "AUTH_GSS", | 1328 | .cr_name = "AUTH_GSS", |
1300 | .crdestroy = gss_destroy_cred, | 1329 | .crdestroy = gss_destroy_cred, |
1301 | .cr_init = gss_cred_init, | 1330 | .cr_init = gss_cred_init, |
1331 | .crbind = rpcauth_generic_bind_cred, | ||
1302 | .crmatch = gss_match, | 1332 | .crmatch = gss_match, |
1303 | .crmarshal = gss_marshal, | 1333 | .crmarshal = gss_marshal, |
1304 | .crrefresh = gss_refresh, | 1334 | .crrefresh = gss_refresh, |
@@ -1310,6 +1340,7 @@ static const struct rpc_credops gss_credops = { | |||
1310 | static const struct rpc_credops gss_nullops = { | 1340 | static const struct rpc_credops gss_nullops = { |
1311 | .cr_name = "AUTH_GSS", | 1341 | .cr_name = "AUTH_GSS", |
1312 | .crdestroy = gss_destroy_cred, | 1342 | .crdestroy = gss_destroy_cred, |
1343 | .crbind = rpcauth_generic_bind_cred, | ||
1313 | .crmatch = gss_match, | 1344 | .crmatch = gss_match, |
1314 | .crmarshal = gss_marshal, | 1345 | .crmarshal = gss_marshal, |
1315 | .crrefresh = gss_refresh_null, | 1346 | .crrefresh = gss_refresh_null, |