diff options
author | Damien Miller <djm@mindrot.org> | 2011-05-15 08:48:05 +1000 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2011-05-15 08:48:05 +1000 |
commit | 555f3b856f2681b46870a66386396b49426b9719 (patch) | |
tree | 88756b47f05c76c5afd5ce739aa26a7b3f124809 | |
parent | f4b32aad05cb65caa6eabe09049750b3c8a29cf3 (diff) |
- djm@cvs.openbsd.org 2011/05/08 12:52:01
[PROTOCOL.mux clientloop.c clientloop.h mux.c]
improve our behaviour when TTY allocation fails: if we are in
RequestTTY=auto mode (the default), then do not treat at TTY
allocation error as fatal but rather just restore the local TTY
to cooked mode and continue. This is more graceful on devices that
never allocate TTYs.
If RequestTTY is set to "yes" or "force", then failure to allocate
a TTY is fatal.
ok markus@
-rw-r--r-- | ChangeLog | 12 | ||||
-rw-r--r-- | PROTOCOL.mux | 11 | ||||
-rw-r--r-- | clientloop.c | 53 | ||||
-rw-r--r-- | clientloop.h | 4 | ||||
-rw-r--r-- | mux.c | 60 |
5 files changed, 111 insertions, 29 deletions
@@ -50,6 +50,18 @@ | |||
50 | - jmc@cvs.openbsd.org 2011/05/07 23:20:25 | 50 | - jmc@cvs.openbsd.org 2011/05/07 23:20:25 |
51 | [ssh.1] | 51 | [ssh.1] |
52 | +.It RequestTTY | 52 | +.It RequestTTY |
53 | - djm@cvs.openbsd.org 2011/05/08 12:52:01 | ||
54 | [PROTOCOL.mux clientloop.c clientloop.h mux.c] | ||
55 | improve our behaviour when TTY allocation fails: if we are in | ||
56 | RequestTTY=auto mode (the default), then do not treat at TTY | ||
57 | allocation error as fatal but rather just restore the local TTY | ||
58 | to cooked mode and continue. This is more graceful on devices that | ||
59 | never allocate TTYs. | ||
60 | |||
61 | If RequestTTY is set to "yes" or "force", then failure to allocate | ||
62 | a TTY is fatal. | ||
63 | |||
64 | ok markus@ | ||
53 | 65 | ||
54 | 20110510 | 66 | 20110510 |
55 | - (dtucker) [openbsd-compat/openssl-compat.{c,h}] Bug #1882: fix | 67 | - (dtucker) [openbsd-compat/openssl-compat.{c,h}] Bug #1882: fix |
diff --git a/PROTOCOL.mux b/PROTOCOL.mux index 3da9e37ae..9ad256602 100644 --- a/PROTOCOL.mux +++ b/PROTOCOL.mux | |||
@@ -73,6 +73,13 @@ non-multiplexed ssh(1) connection. Two additional cases that the | |||
73 | client must cope with are it receiving a signal itself and the | 73 | client must cope with are it receiving a signal itself and the |
74 | server disconnecting without sending an exit message. | 74 | server disconnecting without sending an exit message. |
75 | 75 | ||
76 | A master may also send a MUX_S_TTY_ALLOC_FAIL before MUX_S_EXIT_MESSAGE | ||
77 | if remote TTY allocation was unsuccessful. The client may use this to | ||
78 | return its local tty to "cooked" mode. | ||
79 | |||
80 | uint32 MUX_S_TTY_ALLOC_FAIL | ||
81 | uint32 session id | ||
82 | |||
76 | 3. Health checks | 83 | 3. Health checks |
77 | 84 | ||
78 | The client may request a health check/PID report from a server: | 85 | 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: | |||
197 | #define MUX_S_ALIVE 0x80000005 | 204 | #define MUX_S_ALIVE 0x80000005 |
198 | #define MUX_S_SESSION_OPENED 0x80000006 | 205 | #define MUX_S_SESSION_OPENED 0x80000006 |
199 | #define MUX_S_REMOTE_PORT 0x80000007 | 206 | #define MUX_S_REMOTE_PORT 0x80000007 |
207 | #define MUX_S_TTY_ALLOC_FAIL 0x80000008 | ||
200 | 208 | ||
201 | #define MUX_FWD_LOCAL 1 | 209 | #define MUX_FWD_LOCAL 1 |
202 | #define MUX_FWD_REMOTE 2 | 210 | #define MUX_FWD_REMOTE 2 |
@@ -208,7 +216,6 @@ XXX lock (maybe) | |||
208 | XXX watch in/out traffic (pre/post crypto) | 216 | XXX watch in/out traffic (pre/post crypto) |
209 | XXX inject packet (what about replies) | 217 | XXX inject packet (what about replies) |
210 | XXX server->client error/warning notifications | 218 | XXX server->client error/warning notifications |
211 | XXX port0 rfwd (need custom response message) | ||
212 | XXX send signals via mux | 219 | XXX send signals via mux |
213 | 220 | ||
214 | $OpenBSD: PROTOCOL.mux,v 1.6 2011/05/06 22:20:10 djm Exp $ | 221 | $OpenBSD: PROTOCOL.mux,v 1.7 2011/05/08 12:52:01 djm Exp $ |
diff --git a/clientloop.c b/clientloop.c index 5bd757dfb..ed1d8a238 100644 --- a/clientloop.c +++ b/clientloop.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: clientloop.c,v 1.233 2011/05/06 21:34:32 djm Exp $ */ | 1 | /* $OpenBSD: clientloop.c,v 1.234 2011/05/08 12:52:01 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -174,9 +174,11 @@ struct escape_filter_ctx { | |||
174 | }; | 174 | }; |
175 | 175 | ||
176 | /* Context for channel confirmation replies */ | 176 | /* Context for channel confirmation replies */ |
177 | enum confirm_action { CONFIRM_WARN = 0, CONFIRM_CLOSE, CONFIRM_TTY }; | ||
177 | struct channel_reply_ctx { | 178 | struct channel_reply_ctx { |
178 | const char *request_type; | 179 | const char *request_type; |
179 | int id, do_close; | 180 | int id; |
181 | enum confirm_action action; | ||
180 | }; | 182 | }; |
181 | 183 | ||
182 | /* Global request success/failure callbacks */ | 184 | /* Global request success/failure callbacks */ |
@@ -739,6 +741,15 @@ client_status_confirm(int type, Channel *c, void *ctx) | |||
739 | char errmsg[256]; | 741 | char errmsg[256]; |
740 | int tochan; | 742 | int tochan; |
741 | 743 | ||
744 | /* | ||
745 | * If a TTY was explicitly requested, then a failure to allocate | ||
746 | * one is fatal. | ||
747 | */ | ||
748 | if (cr->action == CONFIRM_TTY && | ||
749 | (options.request_tty == REQUEST_TTY_FORCE || | ||
750 | options.request_tty == REQUEST_TTY_YES)) | ||
751 | cr->action = CONFIRM_CLOSE; | ||
752 | |||
742 | /* XXX supress on mux _client_ quietmode */ | 753 | /* XXX supress on mux _client_ quietmode */ |
743 | tochan = options.log_level >= SYSLOG_LEVEL_ERROR && | 754 | tochan = options.log_level >= SYSLOG_LEVEL_ERROR && |
744 | c->ctl_chan != -1 && c->extended_usage == CHAN_EXTENDED_WRITE; | 755 | c->ctl_chan != -1 && c->extended_usage == CHAN_EXTENDED_WRITE; |
@@ -756,14 +767,27 @@ client_status_confirm(int type, Channel *c, void *ctx) | |||
756 | cr->request_type, c->self); | 767 | cr->request_type, c->self); |
757 | } | 768 | } |
758 | /* If error occurred on primary session channel, then exit */ | 769 | /* If error occurred on primary session channel, then exit */ |
759 | if (cr->do_close && c->self == session_ident) | 770 | if (cr->action == CONFIRM_CLOSE && c->self == session_ident) |
760 | fatal("%s", errmsg); | 771 | fatal("%s", errmsg); |
761 | /* If error occurred on mux client, append to their stderr */ | 772 | /* |
762 | if (tochan) | 773 | * If error occurred on mux client, append to |
763 | buffer_append(&c->extended, errmsg, strlen(errmsg)); | 774 | * their stderr. |
764 | else | 775 | */ |
776 | if (tochan) { | ||
777 | buffer_append(&c->extended, errmsg, | ||
778 | strlen(errmsg)); | ||
779 | } else | ||
765 | error("%s", errmsg); | 780 | error("%s", errmsg); |
766 | if (cr->do_close) { | 781 | if (cr->action == CONFIRM_TTY) { |
782 | /* | ||
783 | * If a TTY allocation error occurred, then arrange | ||
784 | * for the correct TTY to leave raw mode. | ||
785 | */ | ||
786 | if (c->self == session_ident) | ||
787 | leave_raw_mode(0); | ||
788 | else | ||
789 | mux_tty_alloc_failed(c); | ||
790 | } else if (cr->action == CONFIRM_CLOSE) { | ||
767 | chan_read_failed(c); | 791 | chan_read_failed(c); |
768 | chan_write_failed(c); | 792 | chan_write_failed(c); |
769 | } | 793 | } |
@@ -778,12 +802,13 @@ client_abandon_status_confirm(Channel *c, void *ctx) | |||
778 | } | 802 | } |
779 | 803 | ||
780 | static void | 804 | static void |
781 | client_expect_confirm(int id, const char *request, int do_close) | 805 | client_expect_confirm(int id, const char *request, |
806 | enum confirm_action action) | ||
782 | { | 807 | { |
783 | struct channel_reply_ctx *cr = xmalloc(sizeof(*cr)); | 808 | struct channel_reply_ctx *cr = xmalloc(sizeof(*cr)); |
784 | 809 | ||
785 | cr->request_type = request; | 810 | cr->request_type = request; |
786 | cr->do_close = do_close; | 811 | cr->action = action; |
787 | 812 | ||
788 | channel_register_status_confirm(id, client_status_confirm, | 813 | channel_register_status_confirm(id, client_status_confirm, |
789 | client_abandon_status_confirm, cr); | 814 | client_abandon_status_confirm, cr); |
@@ -1983,7 +2008,7 @@ client_session2_setup(int id, int want_tty, int want_subsystem, | |||
1983 | memset(&ws, 0, sizeof(ws)); | 2008 | memset(&ws, 0, sizeof(ws)); |
1984 | 2009 | ||
1985 | channel_request_start(id, "pty-req", 1); | 2010 | channel_request_start(id, "pty-req", 1); |
1986 | client_expect_confirm(id, "PTY allocation", 1); | 2011 | client_expect_confirm(id, "PTY allocation", CONFIRM_TTY); |
1987 | packet_put_cstring(term != NULL ? term : ""); | 2012 | packet_put_cstring(term != NULL ? term : ""); |
1988 | packet_put_int((u_int)ws.ws_col); | 2013 | packet_put_int((u_int)ws.ws_col); |
1989 | packet_put_int((u_int)ws.ws_row); | 2014 | packet_put_int((u_int)ws.ws_row); |
@@ -2042,18 +2067,18 @@ client_session2_setup(int id, int want_tty, int want_subsystem, | |||
2042 | debug("Sending subsystem: %.*s", | 2067 | debug("Sending subsystem: %.*s", |
2043 | len, (u_char*)buffer_ptr(cmd)); | 2068 | len, (u_char*)buffer_ptr(cmd)); |
2044 | channel_request_start(id, "subsystem", 1); | 2069 | channel_request_start(id, "subsystem", 1); |
2045 | client_expect_confirm(id, "subsystem", 1); | 2070 | client_expect_confirm(id, "subsystem", CONFIRM_CLOSE); |
2046 | } else { | 2071 | } else { |
2047 | debug("Sending command: %.*s", | 2072 | debug("Sending command: %.*s", |
2048 | len, (u_char*)buffer_ptr(cmd)); | 2073 | len, (u_char*)buffer_ptr(cmd)); |
2049 | channel_request_start(id, "exec", 1); | 2074 | channel_request_start(id, "exec", 1); |
2050 | client_expect_confirm(id, "exec", 1); | 2075 | client_expect_confirm(id, "exec", CONFIRM_CLOSE); |
2051 | } | 2076 | } |
2052 | packet_put_string(buffer_ptr(cmd), buffer_len(cmd)); | 2077 | packet_put_string(buffer_ptr(cmd), buffer_len(cmd)); |
2053 | packet_send(); | 2078 | packet_send(); |
2054 | } else { | 2079 | } else { |
2055 | channel_request_start(id, "shell", 1); | 2080 | channel_request_start(id, "shell", 1); |
2056 | client_expect_confirm(id, "shell", 1); | 2081 | client_expect_confirm(id, "shell", CONFIRM_CLOSE); |
2057 | packet_send(); | 2082 | packet_send(); |
2058 | } | 2083 | } |
2059 | } | 2084 | } |
diff --git a/clientloop.h b/clientloop.h index 37d072906..ad588d14d 100644 --- a/clientloop.h +++ b/clientloop.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: clientloop.h,v 1.26 2011/04/17 22:42:41 djm Exp $ */ | 1 | /* $OpenBSD: clientloop.h,v 1.27 2011/05/08 12:52:01 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
@@ -70,3 +70,5 @@ void client_register_global_confirm(global_confirm_cb *, void *); | |||
70 | void muxserver_listen(void); | 70 | void muxserver_listen(void); |
71 | void muxclient(const char *); | 71 | void muxclient(const char *); |
72 | void mux_exit_message(Channel *, int); | 72 | void mux_exit_message(Channel *, int); |
73 | void mux_tty_alloc_failed(Channel *); | ||
74 | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: mux.c,v 1.27 2011/05/06 21:34:32 djm Exp $ */ | 1 | /* $OpenBSD: mux.c,v 1.28 2011/05/08 12:52:01 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 | * |
@@ -153,6 +153,7 @@ struct mux_master_state { | |||
153 | #define MUX_S_ALIVE 0x80000005 | 153 | #define MUX_S_ALIVE 0x80000005 |
154 | #define MUX_S_SESSION_OPENED 0x80000006 | 154 | #define MUX_S_SESSION_OPENED 0x80000006 |
155 | #define MUX_S_REMOTE_PORT 0x80000007 | 155 | #define MUX_S_REMOTE_PORT 0x80000007 |
156 | #define MUX_S_TTY_ALLOC_FAIL 0x80000008 | ||
156 | 157 | ||
157 | /* type codes for MUX_C_OPEN_FWD and MUX_C_CLOSE_FWD */ | 158 | /* type codes for MUX_C_OPEN_FWD and MUX_C_CLOSE_FWD */ |
158 | #define MUX_FWD_LOCAL 1 | 159 | #define MUX_FWD_LOCAL 1 |
@@ -1054,6 +1055,27 @@ mux_exit_message(Channel *c, int exitval) | |||
1054 | buffer_free(&m); | 1055 | buffer_free(&m); |
1055 | } | 1056 | } |
1056 | 1057 | ||
1058 | void | ||
1059 | mux_tty_alloc_failed(Channel *c) | ||
1060 | { | ||
1061 | Buffer m; | ||
1062 | Channel *mux_chan; | ||
1063 | |||
1064 | debug3("%s: channel %d: TTY alloc failed", __func__, c->self); | ||
1065 | |||
1066 | if ((mux_chan = channel_by_id(c->ctl_chan)) == NULL) | ||
1067 | fatal("%s: channel %d missing mux channel %d", | ||
1068 | __func__, c->self, c->ctl_chan); | ||
1069 | |||
1070 | /* Append exit message packet to control socket output queue */ | ||
1071 | buffer_init(&m); | ||
1072 | buffer_put_int(&m, MUX_S_TTY_ALLOC_FAIL); | ||
1073 | buffer_put_int(&m, c->self); | ||
1074 | |||
1075 | buffer_put_string(&mux_chan->output, buffer_ptr(&m), buffer_len(&m)); | ||
1076 | buffer_free(&m); | ||
1077 | } | ||
1078 | |||
1057 | /* Prepare a mux master to listen on a Unix domain socket. */ | 1079 | /* Prepare a mux master to listen on a Unix domain socket. */ |
1058 | void | 1080 | void |
1059 | muxserver_listen(void) | 1081 | muxserver_listen(void) |
@@ -1612,7 +1634,7 @@ mux_client_request_session(int fd) | |||
1612 | char *e, *term; | 1634 | char *e, *term; |
1613 | u_int i, rid, sid, esid, exitval, type, exitval_seen; | 1635 | u_int i, rid, sid, esid, exitval, type, exitval_seen; |
1614 | extern char **environ; | 1636 | extern char **environ; |
1615 | int devnull; | 1637 | int devnull, rawmode; |
1616 | 1638 | ||
1617 | debug3("%s: entering", __func__); | 1639 | debug3("%s: entering", __func__); |
1618 | 1640 | ||
@@ -1708,6 +1730,7 @@ mux_client_request_session(int fd) | |||
1708 | signal(SIGTERM, control_client_sighandler); | 1730 | signal(SIGTERM, control_client_sighandler); |
1709 | signal(SIGWINCH, control_client_sigrelay); | 1731 | signal(SIGWINCH, control_client_sigrelay); |
1710 | 1732 | ||
1733 | rawmode = tty_flag; | ||
1711 | if (tty_flag) | 1734 | if (tty_flag) |
1712 | enter_raw_mode(options.request_tty == REQUEST_TTY_FORCE); | 1735 | enter_raw_mode(options.request_tty == REQUEST_TTY_FORCE); |
1713 | 1736 | ||
@@ -1723,22 +1746,35 @@ mux_client_request_session(int fd) | |||
1723 | if (mux_client_read_packet(fd, &m) != 0) | 1746 | if (mux_client_read_packet(fd, &m) != 0) |
1724 | break; | 1747 | break; |
1725 | type = buffer_get_int(&m); | 1748 | type = buffer_get_int(&m); |
1726 | if (type != MUX_S_EXIT_MESSAGE) { | 1749 | switch (type) { |
1750 | case MUX_S_TTY_ALLOC_FAIL: | ||
1751 | if ((esid = buffer_get_int(&m)) != sid) | ||
1752 | fatal("%s: tty alloc fail on unknown session: " | ||
1753 | "my id %u theirs %u", | ||
1754 | __func__, sid, esid); | ||
1755 | leave_raw_mode(options.request_tty == | ||
1756 | REQUEST_TTY_FORCE); | ||
1757 | rawmode = 0; | ||
1758 | continue; | ||
1759 | case MUX_S_EXIT_MESSAGE: | ||
1760 | if ((esid = buffer_get_int(&m)) != sid) | ||
1761 | fatal("%s: exit on unknown session: " | ||
1762 | "my id %u theirs %u", | ||
1763 | __func__, sid, esid); | ||
1764 | if (exitval_seen) | ||
1765 | fatal("%s: exitval sent twice", __func__); | ||
1766 | exitval = buffer_get_int(&m); | ||
1767 | exitval_seen = 1; | ||
1768 | continue; | ||
1769 | default: | ||
1727 | e = buffer_get_string(&m, NULL); | 1770 | e = buffer_get_string(&m, NULL); |
1728 | fatal("%s: master returned error: %s", __func__, e); | 1771 | fatal("%s: master returned error: %s", __func__, e); |
1729 | } | 1772 | } |
1730 | if ((esid = buffer_get_int(&m)) != sid) | ||
1731 | fatal("%s: exit on unknown session: my id %u theirs %u", | ||
1732 | __func__, sid, esid); | ||
1733 | debug("%s: master session id: %u", __func__, sid); | ||
1734 | if (exitval_seen) | ||
1735 | fatal("%s: exitval sent twice", __func__); | ||
1736 | exitval = buffer_get_int(&m); | ||
1737 | exitval_seen = 1; | ||
1738 | } | 1773 | } |
1739 | 1774 | ||
1740 | close(fd); | 1775 | close(fd); |
1741 | leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE); | 1776 | if (rawmode) |
1777 | leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE); | ||
1742 | 1778 | ||
1743 | if (muxclient_terminate) { | 1779 | if (muxclient_terminate) { |
1744 | debug2("Exiting on signal %d", muxclient_terminate); | 1780 | debug2("Exiting on signal %d", muxclient_terminate); |