diff options
author | Damien Miller <djm@mindrot.org> | 2008-05-19 15:35:33 +1000 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2008-05-19 15:35:33 +1000 |
commit | 5771ed7d1b5af26bc991151ab977e77bf1e87666 (patch) | |
tree | d24e88330fb1b3b2de2e1ed770ba0f28963c5049 /clientloop.c | |
parent | 7207f64a23a49a719aad3083c068f50e5034ccb8 (diff) |
- djm@cvs.openbsd.org 2008/05/08 13:06:11
[clientloop.c clientloop.h ssh.c]
Use new channel status confirmation callback system to properly deal
with "important" channel requests that fail, in particular command exec,
shell and subsystem requests. Previously we would optimistically assume
that the requests would always succeed, which could cause hangs if they
did not (e.g. when the server runs out of fds) or were unimplemented by
the server (bz #1384)
Also, properly report failing multiplex channel requests via the mux
client stderr (subject to LogLevel in the mux master) - better than
silently failing.
most bits ok markus@ (as part of a larger diff)
Diffstat (limited to 'clientloop.c')
-rw-r--r-- | clientloop.c | 106 |
1 files changed, 73 insertions, 33 deletions
diff --git a/clientloop.c b/clientloop.c index edd801440..c40f2c303 100644 --- a/clientloop.c +++ b/clientloop.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: clientloop.c,v 1.189 2008/05/08 12:02:23 djm Exp $ */ | 1 | /* $OpenBSD: clientloop.c,v 1.190 2008/05/08 13:06:10 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 |
@@ -173,6 +173,11 @@ struct confirm_ctx { | |||
173 | char **env; | 173 | char **env; |
174 | }; | 174 | }; |
175 | 175 | ||
176 | struct channel_reply_ctx { | ||
177 | const char *request_type; | ||
178 | int id, do_close; | ||
179 | }; | ||
180 | |||
176 | /*XXX*/ | 181 | /*XXX*/ |
177 | extern Kex *xxx_kex; | 182 | extern Kex *xxx_kex; |
178 | 183 | ||
@@ -645,25 +650,60 @@ client_process_net_input(fd_set *readset) | |||
645 | } | 650 | } |
646 | 651 | ||
647 | static void | 652 | static void |
648 | client_subsystem_reply(int type, u_int32_t seq, void *ctxt) | 653 | client_status_confirm(int type, Channel *c, void *ctx) |
649 | { | 654 | { |
650 | int id; | 655 | struct channel_reply_ctx *cr = (struct channel_reply_ctx *)ctx; |
651 | Channel *c; | 656 | char errmsg[256]; |
657 | int tochan; | ||
658 | |||
659 | /* XXX supress on mux _client_ quietmode */ | ||
660 | tochan = options.log_level >= SYSLOG_LEVEL_ERROR && | ||
661 | c->ctl_fd != -1 && c->extended_usage == CHAN_EXTENDED_WRITE; | ||
662 | |||
663 | if (type == SSH2_MSG_CHANNEL_SUCCESS) { | ||
664 | debug2("%s request accepted on channel %d", | ||
665 | cr->request_type, c->self); | ||
666 | } else if (type == SSH2_MSG_CHANNEL_FAILURE) { | ||
667 | if (tochan) { | ||
668 | snprintf(errmsg, sizeof(errmsg), | ||
669 | "%s request failed\r\n", cr->request_type); | ||
670 | } else { | ||
671 | snprintf(errmsg, sizeof(errmsg), | ||
672 | "%s request failed on channel %d", | ||
673 | cr->request_type, c->self); | ||
674 | } | ||
675 | /* If error occurred on primary session channel, then exit */ | ||
676 | if (cr->do_close && c->self == session_ident) | ||
677 | fatal("%s", errmsg); | ||
678 | /* If error occurred on mux client, append to their stderr */ | ||
679 | if (tochan) | ||
680 | buffer_append(&c->extended, errmsg, strlen(errmsg)); | ||
681 | else | ||
682 | error("%s", errmsg); | ||
683 | if (cr->do_close) { | ||
684 | chan_read_failed(c); | ||
685 | chan_write_failed(c); | ||
686 | } | ||
687 | } | ||
688 | xfree(cr); | ||
689 | } | ||
652 | 690 | ||
653 | id = packet_get_int(); | 691 | static void |
654 | packet_check_eom(); | 692 | client_abandon_status_confirm(Channel *c, void *ctx) |
693 | { | ||
694 | xfree(ctx); | ||
695 | } | ||
655 | 696 | ||
656 | if ((c = channel_lookup(id)) == NULL) { | 697 | static void |
657 | error("%s: no channel for id %d", __func__, id); | 698 | client_expect_confirm(int id, const char *request, int do_close) |
658 | return; | 699 | { |
659 | } | 700 | struct channel_reply_ctx *cr = xmalloc(sizeof(*cr)); |
660 | 701 | ||
661 | if (type == SSH2_MSG_CHANNEL_SUCCESS) | 702 | cr->request_type = request; |
662 | debug2("Request suceeded on channel %d", id); | 703 | cr->do_close = do_close; |
663 | else if (type == SSH2_MSG_CHANNEL_FAILURE) { | 704 | |
664 | error("Request failed on channel %d", id); | 705 | channel_register_status_confirm(id, client_status_confirm, |
665 | channel_free(c); | 706 | client_abandon_status_confirm, cr); |
666 | } | ||
667 | } | 707 | } |
668 | 708 | ||
669 | static void | 709 | static void |
@@ -698,8 +738,7 @@ client_extra_session2_setup(int id, void *arg) | |||
698 | } | 738 | } |
699 | 739 | ||
700 | client_session2_setup(id, cctx->want_tty, cctx->want_subsys, | 740 | client_session2_setup(id, cctx->want_tty, cctx->want_subsys, |
701 | cctx->term, &cctx->tio, c->rfd, &cctx->cmd, cctx->env, | 741 | cctx->term, &cctx->tio, c->rfd, &cctx->cmd, cctx->env); |
702 | client_subsystem_reply); | ||
703 | 742 | ||
704 | c->open_confirm_ctx = NULL; | 743 | c->open_confirm_ctx = NULL; |
705 | buffer_free(&cctx->cmd); | 744 | buffer_free(&cctx->cmd); |
@@ -1366,7 +1405,9 @@ client_process_buffered_input_packets(void) | |||
1366 | static int | 1405 | static int |
1367 | simple_escape_filter(Channel *c, char *buf, int len) | 1406 | simple_escape_filter(Channel *c, char *buf, int len) |
1368 | { | 1407 | { |
1369 | /* XXX we assume c->extended is writeable */ | 1408 | if (c->extended_usage != CHAN_EXTENDED_WRITE) |
1409 | return 0; | ||
1410 | |||
1370 | return process_escapes(&c->input, &c->output, &c->extended, buf, len); | 1411 | return process_escapes(&c->input, &c->output, &c->extended, buf, len); |
1371 | } | 1412 | } |
1372 | 1413 | ||
@@ -1962,8 +2003,7 @@ client_input_global_request(int type, u_int32_t seq, void *ctxt) | |||
1962 | 2003 | ||
1963 | void | 2004 | void |
1964 | client_session2_setup(int id, int want_tty, int want_subsystem, | 2005 | client_session2_setup(int id, int want_tty, int want_subsystem, |
1965 | const char *term, struct termios *tiop, int in_fd, Buffer *cmd, char **env, | 2006 | const char *term, struct termios *tiop, int in_fd, Buffer *cmd, char **env) |
1966 | dispatch_fn *subsys_repl) | ||
1967 | { | 2007 | { |
1968 | int len; | 2008 | int len; |
1969 | Channel *c = NULL; | 2009 | Channel *c = NULL; |
@@ -1981,7 +2021,8 @@ client_session2_setup(int id, int want_tty, int want_subsystem, | |||
1981 | if (ioctl(in_fd, TIOCGWINSZ, &ws) < 0) | 2021 | if (ioctl(in_fd, TIOCGWINSZ, &ws) < 0) |
1982 | memset(&ws, 0, sizeof(ws)); | 2022 | memset(&ws, 0, sizeof(ws)); |
1983 | 2023 | ||
1984 | channel_request_start(id, "pty-req", 0); | 2024 | channel_request_start(id, "pty-req", 1); |
2025 | client_expect_confirm(id, "PTY allocation", 0); | ||
1985 | packet_put_cstring(term != NULL ? term : ""); | 2026 | packet_put_cstring(term != NULL ? term : ""); |
1986 | packet_put_int((u_int)ws.ws_col); | 2027 | packet_put_int((u_int)ws.ws_col); |
1987 | packet_put_int((u_int)ws.ws_row); | 2028 | packet_put_int((u_int)ws.ws_row); |
@@ -2036,22 +2077,21 @@ client_session2_setup(int id, int want_tty, int want_subsystem, | |||
2036 | if (len > 900) | 2077 | if (len > 900) |
2037 | len = 900; | 2078 | len = 900; |
2038 | if (want_subsystem) { | 2079 | if (want_subsystem) { |
2039 | debug("Sending subsystem: %.*s", len, (u_char*)buffer_ptr(cmd)); | 2080 | debug("Sending subsystem: %.*s", |
2040 | channel_request_start(id, "subsystem", subsys_repl != NULL); | 2081 | len, (u_char*)buffer_ptr(cmd)); |
2041 | if (subsys_repl != NULL) { | 2082 | channel_request_start(id, "subsystem", 1); |
2042 | /* register callback for reply */ | 2083 | client_expect_confirm(id, "subsystem", 1); |
2043 | /* XXX we assume that client_loop has already been called */ | ||
2044 | dispatch_set(SSH2_MSG_CHANNEL_FAILURE, subsys_repl); | ||
2045 | dispatch_set(SSH2_MSG_CHANNEL_SUCCESS, subsys_repl); | ||
2046 | } | ||
2047 | } else { | 2084 | } else { |
2048 | debug("Sending command: %.*s", len, (u_char*)buffer_ptr(cmd)); | 2085 | debug("Sending command: %.*s", |
2049 | channel_request_start(id, "exec", 0); | 2086 | len, (u_char*)buffer_ptr(cmd)); |
2087 | channel_request_start(id, "exec", 1); | ||
2088 | client_expect_confirm(id, "exec", 1); | ||
2050 | } | 2089 | } |
2051 | packet_put_string(buffer_ptr(cmd), buffer_len(cmd)); | 2090 | packet_put_string(buffer_ptr(cmd), buffer_len(cmd)); |
2052 | packet_send(); | 2091 | packet_send(); |
2053 | } else { | 2092 | } else { |
2054 | channel_request_start(id, "shell", 0); | 2093 | channel_request_start(id, "shell", 1); |
2094 | client_expect_confirm(id, "shell", 1); | ||
2055 | packet_send(); | 2095 | packet_send(); |
2056 | } | 2096 | } |
2057 | } | 2097 | } |