diff options
Diffstat (limited to 'clientloop.c')
-rw-r--r-- | clientloop.c | 110 |
1 files changed, 75 insertions, 35 deletions
diff --git a/clientloop.c b/clientloop.c index ed1902363..17628efb5 100644 --- a/clientloop.c +++ b/clientloop.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: clientloop.c,v 1.231 2011/01/16 12:05:59 djm Exp $ */ | 1 | /* $OpenBSD: clientloop.c,v 1.236 2011/06/22 22:08:42 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 |
@@ -134,9 +134,6 @@ extern int muxserver_sock; /* XXX use mux_client_cleanup() instead */ | |||
134 | */ | 134 | */ |
135 | extern char *host; | 135 | extern char *host; |
136 | 136 | ||
137 | /* Force TTY allocation */ | ||
138 | extern int force_tty_flag; | ||
139 | |||
140 | /* | 137 | /* |
141 | * Flag to indicate that we have received a window change signal which has | 138 | * Flag to indicate that we have received a window change signal which has |
142 | * not yet been processed. This will cause a message indicating the new | 139 | * not yet been processed. This will cause a message indicating the new |
@@ -183,7 +180,8 @@ struct escape_filter_ctx { | |||
183 | /* Context for channel confirmation replies */ | 180 | /* Context for channel confirmation replies */ |
184 | struct channel_reply_ctx { | 181 | struct channel_reply_ctx { |
185 | const char *request_type; | 182 | const char *request_type; |
186 | int id, do_close; | 183 | int id; |
184 | enum confirm_action action; | ||
187 | }; | 185 | }; |
188 | 186 | ||
189 | /* Global request success/failure callbacks */ | 187 | /* Global request success/failure callbacks */ |
@@ -269,10 +267,10 @@ static void | |||
269 | set_control_persist_exit_time(void) | 267 | set_control_persist_exit_time(void) |
270 | { | 268 | { |
271 | if (muxserver_sock == -1 || !options.control_persist | 269 | if (muxserver_sock == -1 || !options.control_persist |
272 | || options.control_persist_timeout == 0) | 270 | || options.control_persist_timeout == 0) { |
273 | /* not using a ControlPersist timeout */ | 271 | /* not using a ControlPersist timeout */ |
274 | control_persist_exit_time = 0; | 272 | control_persist_exit_time = 0; |
275 | else if (channel_still_open()) { | 273 | } else if (channel_still_open()) { |
276 | /* some client connections are still open */ | 274 | /* some client connections are still open */ |
277 | if (control_persist_exit_time > 0) | 275 | if (control_persist_exit_time > 0) |
278 | debug2("%s: cancel scheduled exit", __func__); | 276 | debug2("%s: cancel scheduled exit", __func__); |
@@ -666,7 +664,7 @@ client_suspend_self(Buffer *bin, Buffer *bout, Buffer *berr) | |||
666 | atomicio(vwrite, fileno(stderr), buffer_ptr(berr), | 664 | atomicio(vwrite, fileno(stderr), buffer_ptr(berr), |
667 | buffer_len(berr)); | 665 | buffer_len(berr)); |
668 | 666 | ||
669 | leave_raw_mode(force_tty_flag); | 667 | leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE); |
670 | 668 | ||
671 | /* | 669 | /* |
672 | * Free (and clear) the buffer to reduce the amount of data that gets | 670 | * Free (and clear) the buffer to reduce the amount of data that gets |
@@ -687,7 +685,7 @@ client_suspend_self(Buffer *bin, Buffer *bout, Buffer *berr) | |||
687 | buffer_init(bout); | 685 | buffer_init(bout); |
688 | buffer_init(berr); | 686 | buffer_init(berr); |
689 | 687 | ||
690 | enter_raw_mode(force_tty_flag); | 688 | enter_raw_mode(options.request_tty == REQUEST_TTY_FORCE); |
691 | } | 689 | } |
692 | 690 | ||
693 | static void | 691 | static void |
@@ -746,6 +744,15 @@ client_status_confirm(int type, Channel *c, void *ctx) | |||
746 | char errmsg[256]; | 744 | char errmsg[256]; |
747 | int tochan; | 745 | int tochan; |
748 | 746 | ||
747 | /* | ||
748 | * If a TTY was explicitly requested, then a failure to allocate | ||
749 | * one is fatal. | ||
750 | */ | ||
751 | if (cr->action == CONFIRM_TTY && | ||
752 | (options.request_tty == REQUEST_TTY_FORCE || | ||
753 | options.request_tty == REQUEST_TTY_YES)) | ||
754 | cr->action = CONFIRM_CLOSE; | ||
755 | |||
749 | /* XXX supress on mux _client_ quietmode */ | 756 | /* XXX supress on mux _client_ quietmode */ |
750 | tochan = options.log_level >= SYSLOG_LEVEL_ERROR && | 757 | tochan = options.log_level >= SYSLOG_LEVEL_ERROR && |
751 | c->ctl_chan != -1 && c->extended_usage == CHAN_EXTENDED_WRITE; | 758 | c->ctl_chan != -1 && c->extended_usage == CHAN_EXTENDED_WRITE; |
@@ -763,14 +770,27 @@ client_status_confirm(int type, Channel *c, void *ctx) | |||
763 | cr->request_type, c->self); | 770 | cr->request_type, c->self); |
764 | } | 771 | } |
765 | /* If error occurred on primary session channel, then exit */ | 772 | /* If error occurred on primary session channel, then exit */ |
766 | if (cr->do_close && c->self == session_ident) | 773 | if (cr->action == CONFIRM_CLOSE && c->self == session_ident) |
767 | fatal("%s", errmsg); | 774 | fatal("%s", errmsg); |
768 | /* If error occurred on mux client, append to their stderr */ | 775 | /* |
769 | if (tochan) | 776 | * If error occurred on mux client, append to |
770 | buffer_append(&c->extended, errmsg, strlen(errmsg)); | 777 | * their stderr. |
771 | else | 778 | */ |
779 | if (tochan) { | ||
780 | buffer_append(&c->extended, errmsg, | ||
781 | strlen(errmsg)); | ||
782 | } else | ||
772 | error("%s", errmsg); | 783 | error("%s", errmsg); |
773 | if (cr->do_close) { | 784 | if (cr->action == CONFIRM_TTY) { |
785 | /* | ||
786 | * If a TTY allocation error occurred, then arrange | ||
787 | * for the correct TTY to leave raw mode. | ||
788 | */ | ||
789 | if (c->self == session_ident) | ||
790 | leave_raw_mode(0); | ||
791 | else | ||
792 | mux_tty_alloc_failed(c); | ||
793 | } else if (cr->action == CONFIRM_CLOSE) { | ||
774 | chan_read_failed(c); | 794 | chan_read_failed(c); |
775 | chan_write_failed(c); | 795 | chan_write_failed(c); |
776 | } | 796 | } |
@@ -784,13 +804,14 @@ client_abandon_status_confirm(Channel *c, void *ctx) | |||
784 | xfree(ctx); | 804 | xfree(ctx); |
785 | } | 805 | } |
786 | 806 | ||
787 | static void | 807 | void |
788 | client_expect_confirm(int id, const char *request, int do_close) | 808 | client_expect_confirm(int id, const char *request, |
809 | enum confirm_action action) | ||
789 | { | 810 | { |
790 | struct channel_reply_ctx *cr = xmalloc(sizeof(*cr)); | 811 | struct channel_reply_ctx *cr = xmalloc(sizeof(*cr)); |
791 | 812 | ||
792 | cr->request_type = request; | 813 | cr->request_type = request; |
793 | cr->do_close = do_close; | 814 | cr->action = action; |
794 | 815 | ||
795 | channel_register_status_confirm(id, client_status_confirm, | 816 | channel_register_status_confirm(id, client_status_confirm, |
796 | client_abandon_status_confirm, cr); | 817 | client_abandon_status_confirm, cr); |
@@ -830,7 +851,7 @@ process_cmdline(void) | |||
830 | bzero(&fwd, sizeof(fwd)); | 851 | bzero(&fwd, sizeof(fwd)); |
831 | fwd.listen_host = fwd.connect_host = NULL; | 852 | fwd.listen_host = fwd.connect_host = NULL; |
832 | 853 | ||
833 | leave_raw_mode(force_tty_flag); | 854 | leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE); |
834 | handler = signal(SIGINT, SIG_IGN); | 855 | handler = signal(SIGINT, SIG_IGN); |
835 | cmd = s = read_passphrase("\r\nssh> ", RP_ECHO); | 856 | cmd = s = read_passphrase("\r\nssh> ", RP_ECHO); |
836 | if (s == NULL) | 857 | if (s == NULL) |
@@ -934,7 +955,7 @@ process_cmdline(void) | |||
934 | 955 | ||
935 | out: | 956 | out: |
936 | signal(SIGINT, handler); | 957 | signal(SIGINT, handler); |
937 | enter_raw_mode(force_tty_flag); | 958 | enter_raw_mode(options.request_tty == REQUEST_TTY_FORCE); |
938 | if (cmd) | 959 | if (cmd) |
939 | xfree(cmd); | 960 | xfree(cmd); |
940 | if (fwd.listen_host != NULL) | 961 | if (fwd.listen_host != NULL) |
@@ -1053,7 +1074,8 @@ process_escapes(Channel *c, Buffer *bin, Buffer *bout, Buffer *berr, | |||
1053 | * more new connections). | 1074 | * more new connections). |
1054 | */ | 1075 | */ |
1055 | /* Restore tty modes. */ | 1076 | /* Restore tty modes. */ |
1056 | leave_raw_mode(force_tty_flag); | 1077 | leave_raw_mode( |
1078 | options.request_tty == REQUEST_TTY_FORCE); | ||
1057 | 1079 | ||
1058 | /* Stop listening for new connections. */ | 1080 | /* Stop listening for new connections. */ |
1059 | channel_stop_listening(); | 1081 | channel_stop_listening(); |
@@ -1348,7 +1370,7 @@ client_channel_closed(int id, void *arg) | |||
1348 | { | 1370 | { |
1349 | channel_cancel_cleanup(id); | 1371 | channel_cancel_cleanup(id); |
1350 | session_closed = 1; | 1372 | session_closed = 1; |
1351 | leave_raw_mode(force_tty_flag); | 1373 | leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE); |
1352 | } | 1374 | } |
1353 | 1375 | ||
1354 | /* | 1376 | /* |
@@ -1419,18 +1441,21 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1419 | signal(SIGWINCH, window_change_handler); | 1441 | signal(SIGWINCH, window_change_handler); |
1420 | 1442 | ||
1421 | if (have_pty) | 1443 | if (have_pty) |
1422 | enter_raw_mode(force_tty_flag); | 1444 | enter_raw_mode(options.request_tty == REQUEST_TTY_FORCE); |
1423 | 1445 | ||
1424 | if (compat20) { | 1446 | if (compat20) { |
1425 | session_ident = ssh2_chan_id; | 1447 | session_ident = ssh2_chan_id; |
1426 | if (escape_char_arg != SSH_ESCAPECHAR_NONE) | 1448 | if (session_ident != -1) { |
1427 | channel_register_filter(session_ident, | 1449 | if (escape_char_arg != SSH_ESCAPECHAR_NONE) { |
1428 | client_simple_escape_filter, NULL, | 1450 | channel_register_filter(session_ident, |
1429 | client_filter_cleanup, | 1451 | client_simple_escape_filter, NULL, |
1430 | client_new_escape_filter_ctx(escape_char_arg)); | 1452 | client_filter_cleanup, |
1431 | if (session_ident != -1) | 1453 | client_new_escape_filter_ctx( |
1454 | escape_char_arg)); | ||
1455 | } | ||
1432 | channel_register_cleanup(session_ident, | 1456 | channel_register_cleanup(session_ident, |
1433 | client_channel_closed, 0); | 1457 | client_channel_closed, 0); |
1458 | } | ||
1434 | } else { | 1459 | } else { |
1435 | /* Check if we should immediately send eof on stdin. */ | 1460 | /* Check if we should immediately send eof on stdin. */ |
1436 | client_check_initial_eof_on_stdin(); | 1461 | client_check_initial_eof_on_stdin(); |
@@ -1569,7 +1594,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1569 | channel_free_all(); | 1594 | channel_free_all(); |
1570 | 1595 | ||
1571 | if (have_pty) | 1596 | if (have_pty) |
1572 | leave_raw_mode(force_tty_flag); | 1597 | leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE); |
1573 | 1598 | ||
1574 | /* restore blocking io */ | 1599 | /* restore blocking io */ |
1575 | if (!isatty(fileno(stdin))) | 1600 | if (!isatty(fileno(stdin))) |
@@ -1995,7 +2020,7 @@ client_session2_setup(int id, int want_tty, int want_subsystem, | |||
1995 | memset(&ws, 0, sizeof(ws)); | 2020 | memset(&ws, 0, sizeof(ws)); |
1996 | 2021 | ||
1997 | channel_request_start(id, "pty-req", 1); | 2022 | channel_request_start(id, "pty-req", 1); |
1998 | client_expect_confirm(id, "PTY allocation", 1); | 2023 | client_expect_confirm(id, "PTY allocation", CONFIRM_TTY); |
1999 | packet_put_cstring(term != NULL ? term : ""); | 2024 | packet_put_cstring(term != NULL ? term : ""); |
2000 | packet_put_int((u_int)ws.ws_col); | 2025 | packet_put_int((u_int)ws.ws_col); |
2001 | packet_put_int((u_int)ws.ws_row); | 2026 | packet_put_int((u_int)ws.ws_row); |
@@ -2054,18 +2079,18 @@ client_session2_setup(int id, int want_tty, int want_subsystem, | |||
2054 | debug("Sending subsystem: %.*s", | 2079 | debug("Sending subsystem: %.*s", |
2055 | len, (u_char*)buffer_ptr(cmd)); | 2080 | len, (u_char*)buffer_ptr(cmd)); |
2056 | channel_request_start(id, "subsystem", 1); | 2081 | channel_request_start(id, "subsystem", 1); |
2057 | client_expect_confirm(id, "subsystem", 1); | 2082 | client_expect_confirm(id, "subsystem", CONFIRM_CLOSE); |
2058 | } else { | 2083 | } else { |
2059 | debug("Sending command: %.*s", | 2084 | debug("Sending command: %.*s", |
2060 | len, (u_char*)buffer_ptr(cmd)); | 2085 | len, (u_char*)buffer_ptr(cmd)); |
2061 | channel_request_start(id, "exec", 1); | 2086 | channel_request_start(id, "exec", 1); |
2062 | client_expect_confirm(id, "exec", 1); | 2087 | client_expect_confirm(id, "exec", CONFIRM_CLOSE); |
2063 | } | 2088 | } |
2064 | packet_put_string(buffer_ptr(cmd), buffer_len(cmd)); | 2089 | packet_put_string(buffer_ptr(cmd), buffer_len(cmd)); |
2065 | packet_send(); | 2090 | packet_send(); |
2066 | } else { | 2091 | } else { |
2067 | channel_request_start(id, "shell", 1); | 2092 | channel_request_start(id, "shell", 1); |
2068 | client_expect_confirm(id, "shell", 1); | 2093 | client_expect_confirm(id, "shell", CONFIRM_CLOSE); |
2069 | packet_send(); | 2094 | packet_send(); |
2070 | } | 2095 | } |
2071 | } | 2096 | } |
@@ -2135,11 +2160,26 @@ client_init_dispatch(void) | |||
2135 | client_init_dispatch_15(); | 2160 | client_init_dispatch_15(); |
2136 | } | 2161 | } |
2137 | 2162 | ||
2163 | void | ||
2164 | client_stop_mux(void) | ||
2165 | { | ||
2166 | if (options.control_path != NULL && muxserver_sock != -1) | ||
2167 | unlink(options.control_path); | ||
2168 | /* | ||
2169 | * If we are in persist mode, signal that we should close when all | ||
2170 | * active channels are closed. | ||
2171 | */ | ||
2172 | if (options.control_persist) { | ||
2173 | session_closed = 1; | ||
2174 | setproctitle("[stopped mux]"); | ||
2175 | } | ||
2176 | } | ||
2177 | |||
2138 | /* client specific fatal cleanup */ | 2178 | /* client specific fatal cleanup */ |
2139 | void | 2179 | void |
2140 | cleanup_exit(int i) | 2180 | cleanup_exit(int i) |
2141 | { | 2181 | { |
2142 | leave_raw_mode(force_tty_flag); | 2182 | leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE); |
2143 | leave_non_blocking(); | 2183 | leave_non_blocking(); |
2144 | if (options.control_path != NULL && muxserver_sock != -1) | 2184 | if (options.control_path != NULL && muxserver_sock != -1) |
2145 | unlink(options.control_path); | 2185 | unlink(options.control_path); |