summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usr.bin/ssh/PROTOCOL.mux11
-rw-r--r--usr.bin/ssh/clientloop.c53
-rw-r--r--usr.bin/ssh/clientloop.h4
-rw-r--r--usr.bin/ssh/mux.c60
4 files changed, 99 insertions, 29 deletions
diff --git a/usr.bin/ssh/PROTOCOL.mux b/usr.bin/ssh/PROTOCOL.mux
index 3da9e37aeb4..9ad2566026b 100644
--- a/usr.bin/ssh/PROTOCOL.mux
+++ b/usr.bin/ssh/PROTOCOL.mux
@@ -73,6 +73,13 @@ non-multiplexed ssh(1) connection. Two additional cases that the
client must cope with are it receiving a signal itself and the
server disconnecting without sending an exit message.
+A master may also send a MUX_S_TTY_ALLOC_FAIL before MUX_S_EXIT_MESSAGE
+if remote TTY allocation was unsuccessful. The client may use this to
+return its local tty to "cooked" mode.
+
+ uint32 MUX_S_TTY_ALLOC_FAIL
+ uint32 session id
+
3. Health checks
The client may request a health check/PID report from a server:
@@ -197,6 +204,7 @@ The MUX_S_PERMISSION_DENIED and MUX_S_FAILURE include a reason:
#define MUX_S_ALIVE 0x80000005
#define MUX_S_SESSION_OPENED 0x80000006
#define MUX_S_REMOTE_PORT 0x80000007
+#define MUX_S_TTY_ALLOC_FAIL 0x80000008
#define MUX_FWD_LOCAL 1
#define MUX_FWD_REMOTE 2
@@ -208,7 +216,6 @@ XXX lock (maybe)
XXX watch in/out traffic (pre/post crypto)
XXX inject packet (what about replies)
XXX server->client error/warning notifications
-XXX port0 rfwd (need custom response message)
XXX send signals via mux
-$OpenBSD: PROTOCOL.mux,v 1.6 2011/05/06 22:20:10 djm Exp $
+$OpenBSD: PROTOCOL.mux,v 1.7 2011/05/08 12:52:01 djm Exp $
diff --git a/usr.bin/ssh/clientloop.c b/usr.bin/ssh/clientloop.c
index 7df1fb652bc..5389be666a4 100644
--- a/usr.bin/ssh/clientloop.c
+++ b/usr.bin/ssh/clientloop.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: clientloop.c,v 1.233 2011/05/06 21:34:32 djm Exp $ */
+/* $OpenBSD: clientloop.c,v 1.234 2011/05/08 12:52:01 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -166,9 +166,11 @@ struct escape_filter_ctx {
};
/* Context for channel confirmation replies */
+enum confirm_action { CONFIRM_WARN = 0, CONFIRM_CLOSE, CONFIRM_TTY };
struct channel_reply_ctx {
const char *request_type;
- int id, do_close;
+ int id;
+ enum confirm_action action;
};
/* Global request success/failure callbacks */
@@ -730,6 +732,15 @@ client_status_confirm(int type, Channel *c, void *ctx)
char errmsg[256];
int tochan;
+ /*
+ * If a TTY was explicitly requested, then a failure to allocate
+ * one is fatal.
+ */
+ if (cr->action == CONFIRM_TTY &&
+ (options.request_tty == REQUEST_TTY_FORCE ||
+ options.request_tty == REQUEST_TTY_YES))
+ cr->action = CONFIRM_CLOSE;
+
/* XXX supress on mux _client_ quietmode */
tochan = options.log_level >= SYSLOG_LEVEL_ERROR &&
c->ctl_chan != -1 && c->extended_usage == CHAN_EXTENDED_WRITE;
@@ -747,14 +758,27 @@ client_status_confirm(int type, Channel *c, void *ctx)
cr->request_type, c->self);
}
/* If error occurred on primary session channel, then exit */
- if (cr->do_close && c->self == session_ident)
+ if (cr->action == CONFIRM_CLOSE && c->self == session_ident)
fatal("%s", errmsg);
- /* If error occurred on mux client, append to their stderr */
- if (tochan)
- buffer_append(&c->extended, errmsg, strlen(errmsg));
- else
+ /*
+ * If error occurred on mux client, append to
+ * their stderr.
+ */
+ if (tochan) {
+ buffer_append(&c->extended, errmsg,
+ strlen(errmsg));
+ } else
error("%s", errmsg);
- if (cr->do_close) {
+ if (cr->action == CONFIRM_TTY) {
+ /*
+ * If a TTY allocation error occurred, then arrange
+ * for the correct TTY to leave raw mode.
+ */
+ if (c->self == session_ident)
+ leave_raw_mode(0);
+ else
+ mux_tty_alloc_failed(c);
+ } else if (cr->action == CONFIRM_CLOSE) {
chan_read_failed(c);
chan_write_failed(c);
}
@@ -769,12 +793,13 @@ client_abandon_status_confirm(Channel *c, void *ctx)
}
static void
-client_expect_confirm(int id, const char *request, int do_close)
+client_expect_confirm(int id, const char *request,
+ enum confirm_action action)
{
struct channel_reply_ctx *cr = xmalloc(sizeof(*cr));
cr->request_type = request;
- cr->do_close = do_close;
+ cr->action = action;
channel_register_status_confirm(id, client_status_confirm,
client_abandon_status_confirm, cr);
@@ -1965,7 +1990,7 @@ client_session2_setup(int id, int want_tty, int want_subsystem,
memset(&ws, 0, sizeof(ws));
channel_request_start(id, "pty-req", 1);
- client_expect_confirm(id, "PTY allocation", 1);
+ client_expect_confirm(id, "PTY allocation", CONFIRM_TTY);
packet_put_cstring(term != NULL ? term : "");
packet_put_int((u_int)ws.ws_col);
packet_put_int((u_int)ws.ws_row);
@@ -2024,18 +2049,18 @@ client_session2_setup(int id, int want_tty, int want_subsystem,
debug("Sending subsystem: %.*s",
len, (u_char*)buffer_ptr(cmd));
channel_request_start(id, "subsystem", 1);
- client_expect_confirm(id, "subsystem", 1);
+ client_expect_confirm(id, "subsystem", CONFIRM_CLOSE);
} else {
debug("Sending command: %.*s",
len, (u_char*)buffer_ptr(cmd));
channel_request_start(id, "exec", 1);
- client_expect_confirm(id, "exec", 1);
+ client_expect_confirm(id, "exec", CONFIRM_CLOSE);
}
packet_put_string(buffer_ptr(cmd), buffer_len(cmd));
packet_send();
} else {
channel_request_start(id, "shell", 1);
- client_expect_confirm(id, "shell", 1);
+ client_expect_confirm(id, "shell", CONFIRM_CLOSE);
packet_send();
}
}
diff --git a/usr.bin/ssh/clientloop.h b/usr.bin/ssh/clientloop.h
index 37d07290628..ad588d14d8b 100644
--- a/usr.bin/ssh/clientloop.h
+++ b/usr.bin/ssh/clientloop.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: clientloop.h,v 1.26 2011/04/17 22:42:41 djm Exp $ */
+/* $OpenBSD: clientloop.h,v 1.27 2011/05/08 12:52:01 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -70,3 +70,5 @@ void client_register_global_confirm(global_confirm_cb *, void *);
void muxserver_listen(void);
void muxclient(const char *);
void mux_exit_message(Channel *, int);
+void mux_tty_alloc_failed(Channel *);
+
diff --git a/usr.bin/ssh/mux.c b/usr.bin/ssh/mux.c
index 4f18f196322..d63edf1939f 100644
--- a/usr.bin/ssh/mux.c
+++ b/usr.bin/ssh/mux.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mux.c,v 1.27 2011/05/06 21:34:32 djm Exp $ */
+/* $OpenBSD: mux.c,v 1.28 2011/05/08 12:52:01 djm Exp $ */
/*
* Copyright (c) 2002-2008 Damien Miller <djm@openbsd.org>
*
@@ -136,6 +136,7 @@ struct mux_master_state {
#define MUX_S_ALIVE 0x80000005
#define MUX_S_SESSION_OPENED 0x80000006
#define MUX_S_REMOTE_PORT 0x80000007
+#define MUX_S_TTY_ALLOC_FAIL 0x80000008
/* type codes for MUX_C_OPEN_FWD and MUX_C_CLOSE_FWD */
#define MUX_FWD_LOCAL 1
@@ -1037,6 +1038,27 @@ mux_exit_message(Channel *c, int exitval)
buffer_free(&m);
}
+void
+mux_tty_alloc_failed(Channel *c)
+{
+ Buffer m;
+ Channel *mux_chan;
+
+ debug3("%s: channel %d: TTY alloc failed", __func__, c->self);
+
+ if ((mux_chan = channel_by_id(c->ctl_chan)) == NULL)
+ fatal("%s: channel %d missing mux channel %d",
+ __func__, c->self, c->ctl_chan);
+
+ /* Append exit message packet to control socket output queue */
+ buffer_init(&m);
+ buffer_put_int(&m, MUX_S_TTY_ALLOC_FAIL);
+ buffer_put_int(&m, c->self);
+
+ buffer_put_string(&mux_chan->output, buffer_ptr(&m), buffer_len(&m));
+ buffer_free(&m);
+}
+
/* Prepare a mux master to listen on a Unix domain socket. */
void
muxserver_listen(void)
@@ -1588,7 +1610,7 @@ mux_client_request_session(int fd)
char *e, *term;
u_int i, rid, sid, esid, exitval, type, exitval_seen;
extern char **environ;
- int devnull;
+ int devnull, rawmode;
debug3("%s: entering", __func__);
@@ -1684,6 +1706,7 @@ mux_client_request_session(int fd)
signal(SIGTERM, control_client_sighandler);
signal(SIGWINCH, control_client_sigrelay);
+ rawmode = tty_flag;
if (tty_flag)
enter_raw_mode(options.request_tty == REQUEST_TTY_FORCE);
@@ -1699,22 +1722,35 @@ mux_client_request_session(int fd)
if (mux_client_read_packet(fd, &m) != 0)
break;
type = buffer_get_int(&m);
- if (type != MUX_S_EXIT_MESSAGE) {
+ switch (type) {
+ case MUX_S_TTY_ALLOC_FAIL:
+ if ((esid = buffer_get_int(&m)) != sid)
+ fatal("%s: tty alloc fail on unknown session: "
+ "my id %u theirs %u",
+ __func__, sid, esid);
+ leave_raw_mode(options.request_tty ==
+ REQUEST_TTY_FORCE);
+ rawmode = 0;
+ continue;
+ case MUX_S_EXIT_MESSAGE:
+ if ((esid = buffer_get_int(&m)) != sid)
+ fatal("%s: exit on unknown session: "
+ "my id %u theirs %u",
+ __func__, sid, esid);
+ if (exitval_seen)
+ fatal("%s: exitval sent twice", __func__);
+ exitval = buffer_get_int(&m);
+ exitval_seen = 1;
+ continue;
+ default:
e = buffer_get_string(&m, NULL);
fatal("%s: master returned error: %s", __func__, e);
}
- if ((esid = buffer_get_int(&m)) != sid)
- fatal("%s: exit on unknown session: my id %u theirs %u",
- __func__, sid, esid);
- debug("%s: master session id: %u", __func__, sid);
- if (exitval_seen)
- fatal("%s: exitval sent twice", __func__);
- exitval = buffer_get_int(&m);
- exitval_seen = 1;
}
close(fd);
- leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE);
+ if (rawmode)
+ leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE);
if (muxclient_terminate) {
debug2("Exiting on signal %d", muxclient_terminate);