aboutsummaryrefslogtreecommitdiffstats
path: root/net/sunrpc/auth_gss
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2008-04-24 14:46:16 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-04-24 14:46:16 -0400
commit563307b2fa15d687abc54bd980b9847ebf0e3231 (patch)
tree7f16be30217a2e66360ede97aa27d07a4ebd7e55 /net/sunrpc/auth_gss
parent10c993a6b5418cb1026775765ba4c70ffb70853d (diff)
parent233607dbbc823caf685e778cabc49fb7f679900b (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.c105
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
114gss_cred_set_ctx(struct rpc_cred *cred, struct gss_cl_ctx *ctx) 114gss_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
127static int
128gss_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
140static const void * 127static 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)
370static struct gss_upcall_msg * 358static struct gss_upcall_msg *
371gss_setup_upcall(struct rpc_clnt *clnt, struct gss_auth *gss_auth, struct rpc_cred *cred) 359gss_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;
856out: 853out:
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
919static 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*/
923static int 943static int
924gss_refresh(struct rpc_task *task) 944gss_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; 959out:
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:
1286static const struct rpc_authops authgss_ops = { 1317static 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 = {
1310static const struct rpc_credops gss_nullops = { 1340static 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,