diff options
author | Damien Miller <djm@mindrot.org> | 2010-01-26 13:26:22 +1100 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2010-01-26 13:26:22 +1100 |
commit | e1537f951fa87e4d070adda82b474b25cf4902ec (patch) | |
tree | 3c9d794dcf7fca1d880ffd9db24b20038d3f800b /clientloop.c | |
parent | f589fd1ea8c352e6bf819733ecd505119a694c51 (diff) |
- djm@cvs.openbsd.org 2010/01/26 01:28:35
[channels.c channels.h clientloop.c clientloop.h mux.c nchan.c ssh.c]
rewrite ssh(1) multiplexing code to a more sensible protocol.
The new multiplexing code uses channels for the listener and
accepted control sockets to make the mux master non-blocking, so
no stalls when processing messages from a slave.
avoid use of fatal() in mux master protocol parsing so an errant slave
process cannot take down a running master.
implement requesting of port-forwards over multiplexed sessions. Any
port forwards requested by the slave are added to those the master has
established.
add support for stdio forwarding ("ssh -W host:port ...") in mux slaves.
document master/slave mux protocol so that other tools can use it to
control a running ssh(1). Note: there are no guarantees that this
protocol won't be incompatibly changed (though it is versioned).
feedback Salvador Fandino, dtucker@
channel changes ok markus@
Diffstat (limited to 'clientloop.c')
-rw-r--r-- | clientloop.c | 35 |
1 files changed, 12 insertions, 23 deletions
diff --git a/clientloop.c b/clientloop.c index 5793a6e91..05f4720a1 100644 --- a/clientloop.c +++ b/clientloop.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: clientloop.c,v 1.216 2010/01/09 05:04:24 djm Exp $ */ | 1 | /* $OpenBSD: clientloop.c,v 1.217 2010/01/26 01:28:35 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 |
@@ -121,7 +121,7 @@ extern int stdin_null_flag; | |||
121 | extern int no_shell_flag; | 121 | extern int no_shell_flag; |
122 | 122 | ||
123 | /* Control socket */ | 123 | /* Control socket */ |
124 | extern int muxserver_sock; | 124 | extern int muxserver_sock; /* XXX use mux_client_cleanup() instead */ |
125 | 125 | ||
126 | /* | 126 | /* |
127 | * Name of the host we are connecting to. This is the name given on the | 127 | * Name of the host we are connecting to. This is the name given on the |
@@ -146,7 +146,7 @@ static volatile sig_atomic_t received_signal = 0; | |||
146 | static int in_non_blocking_mode = 0; | 146 | static int in_non_blocking_mode = 0; |
147 | 147 | ||
148 | /* Common data for the client loop code. */ | 148 | /* Common data for the client loop code. */ |
149 | static volatile sig_atomic_t quit_pending; /* Set non-zero to quit the loop. */ | 149 | volatile sig_atomic_t quit_pending; /* Set non-zero to quit the loop. */ |
150 | static int escape_char1; /* Escape character. (proto1 only) */ | 150 | static int escape_char1; /* Escape character. (proto1 only) */ |
151 | static int escape_pending1; /* Last character was an escape (proto1 only) */ | 151 | static int escape_pending1; /* Last character was an escape (proto1 only) */ |
152 | static int last_was_cr; /* Last character was a newline. */ | 152 | static int last_was_cr; /* Last character was a newline. */ |
@@ -564,9 +564,6 @@ client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, | |||
564 | if (packet_have_data_to_write()) | 564 | if (packet_have_data_to_write()) |
565 | FD_SET(connection_out, *writesetp); | 565 | FD_SET(connection_out, *writesetp); |
566 | 566 | ||
567 | if (muxserver_sock != -1) | ||
568 | FD_SET(muxserver_sock, *readsetp); | ||
569 | |||
570 | /* | 567 | /* |
571 | * Wait for something to happen. This will suspend the process until | 568 | * Wait for something to happen. This will suspend the process until |
572 | * some selected descriptor can be read, written, or has some other | 569 | * some selected descriptor can be read, written, or has some other |
@@ -695,7 +692,7 @@ client_status_confirm(int type, Channel *c, void *ctx) | |||
695 | 692 | ||
696 | /* XXX supress on mux _client_ quietmode */ | 693 | /* XXX supress on mux _client_ quietmode */ |
697 | tochan = options.log_level >= SYSLOG_LEVEL_ERROR && | 694 | tochan = options.log_level >= SYSLOG_LEVEL_ERROR && |
698 | c->ctl_fd != -1 && c->extended_usage == CHAN_EXTENDED_WRITE; | 695 | c->ctl_chan != -1 && c->extended_usage == CHAN_EXTENDED_WRITE; |
699 | 696 | ||
700 | if (type == SSH2_MSG_CHANNEL_SUCCESS) { | 697 | if (type == SSH2_MSG_CHANNEL_SUCCESS) { |
701 | debug2("%s request accepted on channel %d", | 698 | debug2("%s request accepted on channel %d", |
@@ -839,6 +836,7 @@ process_cmdline(void) | |||
839 | while (isspace(*++s)) | 836 | while (isspace(*++s)) |
840 | ; | 837 | ; |
841 | 838 | ||
839 | /* XXX update list of forwards in options */ | ||
842 | if (delete) { | 840 | if (delete) { |
843 | cancel_port = 0; | 841 | cancel_port = 0; |
844 | cancel_host = hpdelim(&s); /* may be NULL */ | 842 | cancel_host = hpdelim(&s); /* may be NULL */ |
@@ -936,7 +934,7 @@ process_escapes(Channel *c, Buffer *bin, Buffer *bout, Buffer *berr, | |||
936 | escape_char); | 934 | escape_char); |
937 | buffer_append(berr, string, strlen(string)); | 935 | buffer_append(berr, string, strlen(string)); |
938 | 936 | ||
939 | if (c && c->ctl_fd != -1) { | 937 | if (c && c->ctl_chan != -1) { |
940 | chan_read_failed(c); | 938 | chan_read_failed(c); |
941 | chan_write_failed(c); | 939 | chan_write_failed(c); |
942 | return 0; | 940 | return 0; |
@@ -946,7 +944,7 @@ process_escapes(Channel *c, Buffer *bin, Buffer *bout, Buffer *berr, | |||
946 | 944 | ||
947 | case 'Z' - 64: | 945 | case 'Z' - 64: |
948 | /* XXX support this for mux clients */ | 946 | /* XXX support this for mux clients */ |
949 | if (c && c->ctl_fd != -1) { | 947 | if (c && c->ctl_chan != -1) { |
950 | noescape: | 948 | noescape: |
951 | snprintf(string, sizeof string, | 949 | snprintf(string, sizeof string, |
952 | "%c%c escape not available to " | 950 | "%c%c escape not available to " |
@@ -991,7 +989,7 @@ process_escapes(Channel *c, Buffer *bin, Buffer *bout, Buffer *berr, | |||
991 | continue; | 989 | continue; |
992 | 990 | ||
993 | case '&': | 991 | case '&': |
994 | if (c && c->ctl_fd != -1) | 992 | if (c && c->ctl_chan != -1) |
995 | goto noescape; | 993 | goto noescape; |
996 | /* | 994 | /* |
997 | * Detach the program (continue to serve | 995 | * Detach the program (continue to serve |
@@ -1042,7 +1040,7 @@ process_escapes(Channel *c, Buffer *bin, Buffer *bout, Buffer *berr, | |||
1042 | continue; | 1040 | continue; |
1043 | 1041 | ||
1044 | case '?': | 1042 | case '?': |
1045 | if (c && c->ctl_fd != -1) { | 1043 | if (c && c->ctl_chan != -1) { |
1046 | snprintf(string, sizeof string, | 1044 | snprintf(string, sizeof string, |
1047 | "%c?\r\n\ | 1045 | "%c?\r\n\ |
1048 | Supported escape sequences:\r\n\ | 1046 | Supported escape sequences:\r\n\ |
@@ -1091,7 +1089,7 @@ Supported escape sequences:\r\n\ | |||
1091 | continue; | 1089 | continue; |
1092 | 1090 | ||
1093 | case 'C': | 1091 | case 'C': |
1094 | if (c && c->ctl_fd != -1) | 1092 | if (c && c->ctl_chan != -1) |
1095 | goto noescape; | 1093 | goto noescape; |
1096 | process_cmdline(); | 1094 | process_cmdline(); |
1097 | continue; | 1095 | continue; |
@@ -1327,8 +1325,6 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1327 | connection_in = packet_get_connection_in(); | 1325 | connection_in = packet_get_connection_in(); |
1328 | connection_out = packet_get_connection_out(); | 1326 | connection_out = packet_get_connection_out(); |
1329 | max_fd = MAX(connection_in, connection_out); | 1327 | max_fd = MAX(connection_in, connection_out); |
1330 | if (muxserver_sock != -1) | ||
1331 | max_fd = MAX(max_fd, muxserver_sock); | ||
1332 | 1328 | ||
1333 | if (!compat20) { | 1329 | if (!compat20) { |
1334 | /* enable nonblocking unless tty */ | 1330 | /* enable nonblocking unless tty */ |
@@ -1446,12 +1442,6 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1446 | /* Buffer input from the connection. */ | 1442 | /* Buffer input from the connection. */ |
1447 | client_process_net_input(readset); | 1443 | client_process_net_input(readset); |
1448 | 1444 | ||
1449 | /* Accept control connections. */ | ||
1450 | if (muxserver_sock != -1 &&FD_ISSET(muxserver_sock, readset)) { | ||
1451 | if (muxserver_accept_control()) | ||
1452 | quit_pending = 1; | ||
1453 | } | ||
1454 | |||
1455 | if (quit_pending) | 1445 | if (quit_pending) |
1456 | break; | 1446 | break; |
1457 | 1447 | ||
@@ -1859,9 +1849,8 @@ client_input_channel_req(int type, u_int32_t seq, void *ctxt) | |||
1859 | chan_rcvd_eow(c); | 1849 | chan_rcvd_eow(c); |
1860 | } else if (strcmp(rtype, "exit-status") == 0) { | 1850 | } else if (strcmp(rtype, "exit-status") == 0) { |
1861 | exitval = packet_get_int(); | 1851 | exitval = packet_get_int(); |
1862 | if (c->ctl_fd != -1) { | 1852 | if (c->ctl_chan != -1) { |
1863 | /* Dispatch to mux client */ | 1853 | mux_exit_message(c, exitval); |
1864 | atomicio(vwrite, c->ctl_fd, &exitval, sizeof(exitval)); | ||
1865 | success = 1; | 1854 | success = 1; |
1866 | } else if (id == session_ident) { | 1855 | } else if (id == session_ident) { |
1867 | /* Record exit value of local session */ | 1856 | /* Record exit value of local session */ |