summaryrefslogtreecommitdiff
path: root/mux.c
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>2010-05-21 14:57:10 +1000
committerDamien Miller <djm@mindrot.org>2010-05-21 14:57:10 +1000
commitd530f5f471491b6be9edb58a063f2590e4dce48d (patch)
treee536e2b4031a4dd70026ff49c39b02b72af06f30 /mux.c
parentc6afb5f2c095a6a4380cc13a6480abb7614d949f (diff)
- djm@cvs.openbsd.org 2010/05/14 23:29:23
[channels.c channels.h mux.c ssh.c] Pause the mux channel while waiting for reply from aynch callbacks. Prevents misordering of replies if new requests arrive while waiting. Extend channel open confirm callback to allow signalling failure conditions as well as success. Use this to 1) fix a memory leak, 2) start using the above pause mechanism and 3) delay sending a success/ failure message on mux slave session open until we receive a reply from the server. motivated by and with feedback from markus@
Diffstat (limited to 'mux.c')
-rw-r--r--mux.c47
1 files changed, 37 insertions, 10 deletions
diff --git a/mux.c b/mux.c
index ac477a0e7..18dfd99f3 100644
--- a/mux.c
+++ b/mux.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: mux.c,v 1.16 2010/04/23 22:27:38 djm Exp $ */ 1/* $OpenBSD: mux.c,v 1.17 2010/05/14 23:29:23 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2002-2008 Damien Miller <djm@openbsd.org> 3 * Copyright (c) 2002-2008 Damien Miller <djm@openbsd.org>
4 * 4 *
@@ -106,6 +106,7 @@ struct mux_session_confirm_ctx {
106 char *term; 106 char *term;
107 struct termios tio; 107 struct termios tio;
108 char **env; 108 char **env;
109 u_int rid;
109}; 110};
110 111
111/* fd to control socket */ 112/* fd to control socket */
@@ -149,7 +150,7 @@ struct mux_master_state {
149#define MUX_FWD_REMOTE 2 150#define MUX_FWD_REMOTE 2
150#define MUX_FWD_DYNAMIC 3 151#define MUX_FWD_DYNAMIC 3
151 152
152static void mux_session_confirm(int, void *); 153static void mux_session_confirm(int, int, void *);
153 154
154static int process_mux_master_hello(u_int, Channel *, Buffer *, Buffer *); 155static int process_mux_master_hello(u_int, Channel *, Buffer *, Buffer *);
155static int process_mux_new_session(u_int, Channel *, Buffer *, Buffer *); 156static int process_mux_new_session(u_int, Channel *, Buffer *, Buffer *);
@@ -301,6 +302,7 @@ process_mux_new_session(u_int rid, Channel *c, Buffer *m, Buffer *r)
301 /* Reply for SSHMUX_COMMAND_OPEN */ 302 /* Reply for SSHMUX_COMMAND_OPEN */
302 cctx = xcalloc(1, sizeof(*cctx)); 303 cctx = xcalloc(1, sizeof(*cctx));
303 cctx->term = NULL; 304 cctx->term = NULL;
305 cctx->rid = rid;
304 cmd = reserved = NULL; 306 cmd = reserved = NULL;
305 if ((reserved = buffer_get_string_ret(m, NULL)) == NULL || 307 if ((reserved = buffer_get_string_ret(m, NULL)) == NULL ||
306 buffer_get_int_ret(&cctx->want_tty, m) != 0 || 308 buffer_get_int_ret(&cctx->want_tty, m) != 0 ||
@@ -454,14 +456,10 @@ process_mux_new_session(u_int rid, Channel *c, Buffer *m, Buffer *r)
454 456
455 channel_send_open(nc->self); 457 channel_send_open(nc->self);
456 channel_register_open_confirm(nc->self, mux_session_confirm, cctx); 458 channel_register_open_confirm(nc->self, mux_session_confirm, cctx);
459 c->mux_pause = 1; /* stop handling messages until open_confirm done */
457 channel_register_cleanup(nc->self, mux_master_session_cleanup_cb, 1); 460 channel_register_cleanup(nc->self, mux_master_session_cleanup_cb, 1);
458 461
459 /* prepare reply */ 462 /* reply is deferred, sent by mux_session_confirm */
460 /* XXX defer until mux_session_confirm() fires */
461 buffer_put_int(r, MUX_S_SESSION_OPENED);
462 buffer_put_int(r, rid);
463 buffer_put_int(r, nc->self);
464
465 return 0; 463 return 0;
466} 464}
467 465
@@ -1000,17 +998,31 @@ muxserver_listen(void)
1000 998
1001/* Callback on open confirmation in mux master for a mux client session. */ 999/* Callback on open confirmation in mux master for a mux client session. */
1002static void 1000static void
1003mux_session_confirm(int id, void *arg) 1001mux_session_confirm(int id, int success, void *arg)
1004{ 1002{
1005 struct mux_session_confirm_ctx *cctx = arg; 1003 struct mux_session_confirm_ctx *cctx = arg;
1006 const char *display; 1004 const char *display;
1007 Channel *c; 1005 Channel *c, *cc;
1008 int i; 1006 int i;
1007 Buffer reply;
1009 1008
1010 if (cctx == NULL) 1009 if (cctx == NULL)
1011 fatal("%s: cctx == NULL", __func__); 1010 fatal("%s: cctx == NULL", __func__);
1012 if ((c = channel_by_id(id)) == NULL) 1011 if ((c = channel_by_id(id)) == NULL)
1013 fatal("%s: no channel for id %d", __func__, id); 1012 fatal("%s: no channel for id %d", __func__, id);
1013 if ((cc = channel_by_id(c->ctl_chan)) == NULL)
1014 fatal("%s: channel %d lacks control channel %d", __func__,
1015 id, c->ctl_chan);
1016
1017 if (!success) {
1018 debug3("%s: sending failure reply", __func__);
1019 /* prepare reply */
1020 buffer_init(&reply);
1021 buffer_put_int(&reply, MUX_S_FAILURE);
1022 buffer_put_int(&reply, cctx->rid);
1023 buffer_put_cstring(&reply, "Session open refused by peer");
1024 goto done;
1025 }
1014 1026
1015 display = getenv("DISPLAY"); 1027 display = getenv("DISPLAY");
1016 if (cctx->want_x_fwd && options.forward_x11 && display != NULL) { 1028 if (cctx->want_x_fwd && options.forward_x11 && display != NULL) {
@@ -1033,6 +1045,21 @@ mux_session_confirm(int id, void *arg)
1033 client_session2_setup(id, cctx->want_tty, cctx->want_subsys, 1045 client_session2_setup(id, cctx->want_tty, cctx->want_subsys,
1034 cctx->term, &cctx->tio, c->rfd, &cctx->cmd, cctx->env); 1046 cctx->term, &cctx->tio, c->rfd, &cctx->cmd, cctx->env);
1035 1047
1048 debug3("%s: sending success reply", __func__);
1049 /* prepare reply */
1050 buffer_init(&reply);
1051 buffer_put_int(&reply, MUX_S_SESSION_OPENED);
1052 buffer_put_int(&reply, cctx->rid);
1053 buffer_put_int(&reply, c->self);
1054
1055 done:
1056 /* Send reply */
1057 buffer_put_string(&cc->output, buffer_ptr(&reply), buffer_len(&reply));
1058 buffer_free(&reply);
1059
1060 if (cc->mux_pause <= 0)
1061 fatal("%s: mux_pause %d", __func__, cc->mux_pause);
1062 cc->mux_pause = 0; /* start processing messages again */
1036 c->open_confirm_ctx = NULL; 1063 c->open_confirm_ctx = NULL;
1037 buffer_free(&cctx->cmd); 1064 buffer_free(&cctx->cmd);
1038 xfree(cctx->term); 1065 xfree(cctx->term);