aboutsummaryrefslogtreecommitdiffstats
path: root/net/sunrpc/auth_gss
diff options
context:
space:
mode:
author\"J. Bruce Fields\ <bfields@citi.umich.edu>2008-12-23 16:16:37 -0500
committerTrond Myklebust <Trond.Myklebust@netapp.com>2008-12-23 16:16:37 -0500
commit34769fc488b463cb753fc632f8f5ba56c918b7cb (patch)
tree870cf1ac132567ad5683cf9882ab0810fb5acc2a /net/sunrpc/auth_gss
parent5b7ddd4a7b19f913901140ef7807dbf5e2b301cd (diff)
rpc: implement new upcall
Implement the new upcall. We decide which version of the upcall gssd will use (new or old), by creating both pipes (the new one named "gssd", the old one named after the mechanism (e.g., "krb5")), and then waiting to see which version gssd actually opens. We don't permit pipes of the two different types to be opened at once. Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'net/sunrpc/auth_gss')
-rw-r--r--net/sunrpc/auth_gss/auth_gss.c116
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;
83static DECLARE_WAIT_QUEUE_HEAD(pipe_version_waitqueue); 89static DECLARE_WAIT_QUEUE_HEAD(pipe_version_waitqueue);
84 90
85static void gss_free_ctx(struct gss_cl_ctx *); 91static void gss_free_ctx(struct gss_cl_ctx *);
86static struct rpc_pipe_ops gss_upcall_ops; 92static struct rpc_pipe_ops gss_upcall_ops_v0;
93static struct rpc_pipe_ops gss_upcall_ops_v1;
87 94
88static inline struct gss_cl_ctx * 95static inline struct gss_cl_ctx *
89gss_get_ctx(struct gss_cl_ctx *ctx) 96gss_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
231struct gss_upcall_msg { 239struct 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
243static int get_pipe_version(void) 252static 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
365static 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
371static 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
380static 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
356static inline struct gss_upcall_msg * 388static inline struct gss_upcall_msg *
357gss_alloc_msg(struct gss_auth *gss_auth, uid_t uid) 389gss_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
616static int 647static int gss_pipe_open(struct inode *inode, int new_version)
617gss_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);
663out:
626 spin_unlock(&pipe_version_lock); 664 spin_unlock(&pipe_version_lock);
627 return 0; 665 return ret;
666
667}
668
669static int gss_pipe_open_v0(struct inode *inode)
670{
671 return gss_pipe_open(inode, 0);
672}
673
674static int gss_pipe_open_v1(struct inode *inode)
675{
676 return gss_pipe_open(inode, 1);
628} 677}
629 678
630static void 679static 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;
717err_unlink_pipe: 782err_unlink_pipe_0:
718 rpc_unlink(gss_auth->dentry); 783 rpc_unlink(gss_auth->dentry[0]);
784err_unlink_pipe_1:
785 rpc_unlink(gss_auth->dentry[1]);
719err_put_mech: 786err_put_mech:
720 gss_mech_put(gss_auth->mech); 787 gss_mech_put(gss_auth->mech);
721err_free: 788err_free:
@@ -728,7 +795,8 @@ out_dec:
728static void 795static void
729gss_free(struct gss_auth *gss_auth) 796gss_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
1422static struct rpc_pipe_ops gss_upcall_ops = { 1490static 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
1498static 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