diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/sunrpc/auth_gss/auth_gss.c | 116 |
1 files changed, 96 insertions, 20 deletions
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index fe06acd6029b..153b3e11e61a 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c | |||
@@ -72,7 +72,13 @@ struct gss_auth { | |||
72 | struct gss_api_mech *mech; | 72 | struct gss_api_mech *mech; |
73 | enum rpc_gss_svc service; | 73 | enum rpc_gss_svc service; |
74 | struct rpc_clnt *client; | 74 | struct rpc_clnt *client; |
75 | struct dentry *dentry; | 75 | /* |
76 | * There are two upcall pipes; dentry[1], named "gssd", is used | ||
77 | * for the new text-based upcall; dentry[0] is named after the | ||
78 | * mechanism (for example, "krb5") and exists for | ||
79 | * backwards-compatibility with older gssd's. | ||
80 | */ | ||
81 | struct dentry *dentry[2]; | ||
76 | }; | 82 | }; |
77 | 83 | ||
78 | /* pipe_version >= 0 if and only if someone has a pipe open. */ | 84 | /* pipe_version >= 0 if and only if someone has a pipe open. */ |
@@ -83,7 +89,8 @@ static struct rpc_wait_queue pipe_version_rpc_waitqueue; | |||
83 | static DECLARE_WAIT_QUEUE_HEAD(pipe_version_waitqueue); | 89 | static DECLARE_WAIT_QUEUE_HEAD(pipe_version_waitqueue); |
84 | 90 | ||
85 | static void gss_free_ctx(struct gss_cl_ctx *); | 91 | static void gss_free_ctx(struct gss_cl_ctx *); |
86 | static struct rpc_pipe_ops gss_upcall_ops; | 92 | static struct rpc_pipe_ops gss_upcall_ops_v0; |
93 | static struct rpc_pipe_ops gss_upcall_ops_v1; | ||
87 | 94 | ||
88 | static inline struct gss_cl_ctx * | 95 | static inline struct gss_cl_ctx * |
89 | gss_get_ctx(struct gss_cl_ctx *ctx) | 96 | gss_get_ctx(struct gss_cl_ctx *ctx) |
@@ -227,6 +234,7 @@ err: | |||
227 | return p; | 234 | return p; |
228 | } | 235 | } |
229 | 236 | ||
237 | #define UPCALL_BUF_LEN 128 | ||
230 | 238 | ||
231 | struct gss_upcall_msg { | 239 | struct gss_upcall_msg { |
232 | atomic_t count; | 240 | atomic_t count; |
@@ -238,6 +246,7 @@ struct gss_upcall_msg { | |||
238 | struct rpc_wait_queue rpc_waitqueue; | 246 | struct rpc_wait_queue rpc_waitqueue; |
239 | wait_queue_head_t waitqueue; | 247 | wait_queue_head_t waitqueue; |
240 | struct gss_cl_ctx *ctx; | 248 | struct gss_cl_ctx *ctx; |
249 | char databuf[UPCALL_BUF_LEN]; | ||
241 | }; | 250 | }; |
242 | 251 | ||
243 | static int get_pipe_version(void) | 252 | static int get_pipe_version(void) |
@@ -247,7 +256,7 @@ static int get_pipe_version(void) | |||
247 | spin_lock(&pipe_version_lock); | 256 | spin_lock(&pipe_version_lock); |
248 | if (pipe_version >= 0) { | 257 | if (pipe_version >= 0) { |
249 | atomic_inc(&pipe_users); | 258 | atomic_inc(&pipe_users); |
250 | ret = 0; | 259 | ret = pipe_version; |
251 | } else | 260 | } else |
252 | ret = -EAGAIN; | 261 | ret = -EAGAIN; |
253 | spin_unlock(&pipe_version_lock); | 262 | spin_unlock(&pipe_version_lock); |
@@ -353,6 +362,29 @@ gss_upcall_callback(struct rpc_task *task) | |||
353 | gss_release_msg(gss_msg); | 362 | gss_release_msg(gss_msg); |
354 | } | 363 | } |
355 | 364 | ||
365 | static void gss_encode_v0_msg(struct gss_upcall_msg *gss_msg) | ||
366 | { | ||
367 | gss_msg->msg.data = &gss_msg->uid; | ||
368 | gss_msg->msg.len = sizeof(gss_msg->uid); | ||
369 | } | ||
370 | |||
371 | static void gss_encode_v1_msg(struct gss_upcall_msg *gss_msg) | ||
372 | { | ||
373 | gss_msg->msg.len = sprintf(gss_msg->databuf, "mech=%s uid=%d\n", | ||
374 | gss_msg->auth->mech->gm_name, | ||
375 | gss_msg->uid); | ||
376 | gss_msg->msg.data = gss_msg->databuf; | ||
377 | BUG_ON(gss_msg->msg.len > UPCALL_BUF_LEN); | ||
378 | } | ||
379 | |||
380 | static void gss_encode_msg(struct gss_upcall_msg *gss_msg) | ||
381 | { | ||
382 | if (pipe_version == 0) | ||
383 | gss_encode_v0_msg(gss_msg); | ||
384 | else /* pipe_version == 1 */ | ||
385 | gss_encode_v1_msg(gss_msg); | ||
386 | } | ||
387 | |||
356 | static inline struct gss_upcall_msg * | 388 | static inline struct gss_upcall_msg * |
357 | gss_alloc_msg(struct gss_auth *gss_auth, uid_t uid) | 389 | gss_alloc_msg(struct gss_auth *gss_auth, uid_t uid) |
358 | { | 390 | { |
@@ -367,15 +399,14 @@ gss_alloc_msg(struct gss_auth *gss_auth, uid_t uid) | |||
367 | kfree(gss_msg); | 399 | kfree(gss_msg); |
368 | return ERR_PTR(vers); | 400 | return ERR_PTR(vers); |
369 | } | 401 | } |
370 | gss_msg->inode = RPC_I(gss_auth->dentry->d_inode); | 402 | gss_msg->inode = RPC_I(gss_auth->dentry[vers]->d_inode); |
371 | INIT_LIST_HEAD(&gss_msg->list); | 403 | INIT_LIST_HEAD(&gss_msg->list); |
372 | rpc_init_wait_queue(&gss_msg->rpc_waitqueue, "RPCSEC_GSS upcall waitq"); | 404 | rpc_init_wait_queue(&gss_msg->rpc_waitqueue, "RPCSEC_GSS upcall waitq"); |
373 | init_waitqueue_head(&gss_msg->waitqueue); | 405 | init_waitqueue_head(&gss_msg->waitqueue); |
374 | atomic_set(&gss_msg->count, 1); | 406 | atomic_set(&gss_msg->count, 1); |
375 | gss_msg->msg.data = &gss_msg->uid; | ||
376 | gss_msg->msg.len = sizeof(gss_msg->uid); | ||
377 | gss_msg->uid = uid; | 407 | gss_msg->uid = uid; |
378 | gss_msg->auth = gss_auth; | 408 | gss_msg->auth = gss_auth; |
409 | gss_encode_msg(gss_msg); | ||
379 | return gss_msg; | 410 | return gss_msg; |
380 | } | 411 | } |
381 | 412 | ||
@@ -613,18 +644,36 @@ out: | |||
613 | return err; | 644 | return err; |
614 | } | 645 | } |
615 | 646 | ||
616 | static int | 647 | static int gss_pipe_open(struct inode *inode, int new_version) |
617 | gss_pipe_open(struct inode *inode) | ||
618 | { | 648 | { |
649 | int ret = 0; | ||
650 | |||
619 | spin_lock(&pipe_version_lock); | 651 | spin_lock(&pipe_version_lock); |
620 | if (pipe_version < 0) { | 652 | if (pipe_version < 0) { |
621 | pipe_version = 0; | 653 | /* First open of any gss pipe determines the version: */ |
654 | pipe_version = new_version; | ||
622 | rpc_wake_up(&pipe_version_rpc_waitqueue); | 655 | rpc_wake_up(&pipe_version_rpc_waitqueue); |
623 | wake_up(&pipe_version_waitqueue); | 656 | wake_up(&pipe_version_waitqueue); |
657 | } else if (pipe_version != new_version) { | ||
658 | /* Trying to open a pipe of a different version */ | ||
659 | ret = -EBUSY; | ||
660 | goto out; | ||
624 | } | 661 | } |
625 | atomic_inc(&pipe_users); | 662 | atomic_inc(&pipe_users); |
663 | out: | ||
626 | spin_unlock(&pipe_version_lock); | 664 | spin_unlock(&pipe_version_lock); |
627 | return 0; | 665 | return ret; |
666 | |||
667 | } | ||
668 | |||
669 | static int gss_pipe_open_v0(struct inode *inode) | ||
670 | { | ||
671 | return gss_pipe_open(inode, 0); | ||
672 | } | ||
673 | |||
674 | static int gss_pipe_open_v1(struct inode *inode) | ||
675 | { | ||
676 | return gss_pipe_open(inode, 1); | ||
628 | } | 677 | } |
629 | 678 | ||
630 | static void | 679 | static void |
@@ -702,20 +751,38 @@ gss_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor) | |||
702 | atomic_set(&auth->au_count, 1); | 751 | atomic_set(&auth->au_count, 1); |
703 | kref_init(&gss_auth->kref); | 752 | kref_init(&gss_auth->kref); |
704 | 753 | ||
705 | gss_auth->dentry = rpc_mkpipe(clnt->cl_dentry, gss_auth->mech->gm_name, | 754 | /* |
706 | clnt, &gss_upcall_ops, RPC_PIPE_WAIT_FOR_OPEN); | 755 | * Note: if we created the old pipe first, then someone who |
707 | if (IS_ERR(gss_auth->dentry)) { | 756 | * examined the directory at the right moment might conclude |
708 | err = PTR_ERR(gss_auth->dentry); | 757 | * that we supported only the old pipe. So we instead create |
758 | * the new pipe first. | ||
759 | */ | ||
760 | gss_auth->dentry[1] = rpc_mkpipe(clnt->cl_dentry, | ||
761 | "gssd", | ||
762 | clnt, &gss_upcall_ops_v1, | ||
763 | RPC_PIPE_WAIT_FOR_OPEN); | ||
764 | if (IS_ERR(gss_auth->dentry[1])) { | ||
765 | err = PTR_ERR(gss_auth->dentry[1]); | ||
709 | goto err_put_mech; | 766 | goto err_put_mech; |
710 | } | 767 | } |
711 | 768 | ||
769 | gss_auth->dentry[0] = rpc_mkpipe(clnt->cl_dentry, | ||
770 | gss_auth->mech->gm_name, | ||
771 | clnt, &gss_upcall_ops_v0, | ||
772 | RPC_PIPE_WAIT_FOR_OPEN); | ||
773 | if (IS_ERR(gss_auth->dentry[0])) { | ||
774 | err = PTR_ERR(gss_auth->dentry[0]); | ||
775 | goto err_unlink_pipe_1; | ||
776 | } | ||
712 | err = rpcauth_init_credcache(auth); | 777 | err = rpcauth_init_credcache(auth); |
713 | if (err) | 778 | if (err) |
714 | goto err_unlink_pipe; | 779 | goto err_unlink_pipe_0; |
715 | 780 | ||
716 | return auth; | 781 | return auth; |
717 | err_unlink_pipe: | 782 | err_unlink_pipe_0: |
718 | rpc_unlink(gss_auth->dentry); | 783 | rpc_unlink(gss_auth->dentry[0]); |
784 | err_unlink_pipe_1: | ||
785 | rpc_unlink(gss_auth->dentry[1]); | ||
719 | err_put_mech: | 786 | err_put_mech: |
720 | gss_mech_put(gss_auth->mech); | 787 | gss_mech_put(gss_auth->mech); |
721 | err_free: | 788 | err_free: |
@@ -728,7 +795,8 @@ out_dec: | |||
728 | static void | 795 | static void |
729 | gss_free(struct gss_auth *gss_auth) | 796 | gss_free(struct gss_auth *gss_auth) |
730 | { | 797 | { |
731 | rpc_unlink(gss_auth->dentry); | 798 | rpc_unlink(gss_auth->dentry[1]); |
799 | rpc_unlink(gss_auth->dentry[0]); | ||
732 | gss_mech_put(gss_auth->mech); | 800 | gss_mech_put(gss_auth->mech); |
733 | 801 | ||
734 | kfree(gss_auth); | 802 | kfree(gss_auth); |
@@ -1419,11 +1487,19 @@ static const struct rpc_credops gss_nullops = { | |||
1419 | .crunwrap_resp = gss_unwrap_resp, | 1487 | .crunwrap_resp = gss_unwrap_resp, |
1420 | }; | 1488 | }; |
1421 | 1489 | ||
1422 | static struct rpc_pipe_ops gss_upcall_ops = { | 1490 | static struct rpc_pipe_ops gss_upcall_ops_v0 = { |
1491 | .upcall = gss_pipe_upcall, | ||
1492 | .downcall = gss_pipe_downcall, | ||
1493 | .destroy_msg = gss_pipe_destroy_msg, | ||
1494 | .open_pipe = gss_pipe_open_v0, | ||
1495 | .release_pipe = gss_pipe_release, | ||
1496 | }; | ||
1497 | |||
1498 | static struct rpc_pipe_ops gss_upcall_ops_v1 = { | ||
1423 | .upcall = gss_pipe_upcall, | 1499 | .upcall = gss_pipe_upcall, |
1424 | .downcall = gss_pipe_downcall, | 1500 | .downcall = gss_pipe_downcall, |
1425 | .destroy_msg = gss_pipe_destroy_msg, | 1501 | .destroy_msg = gss_pipe_destroy_msg, |
1426 | .open_pipe = gss_pipe_open, | 1502 | .open_pipe = gss_pipe_open_v1, |
1427 | .release_pipe = gss_pipe_release, | 1503 | .release_pipe = gss_pipe_release, |
1428 | }; | 1504 | }; |
1429 | 1505 | ||