diff options
author | Darren Tucker <dtucker@zip.com.au> | 2008-06-13 04:49:33 +1000 |
---|---|---|
committer | Darren Tucker <dtucker@zip.com.au> | 2008-06-13 04:49:33 +1000 |
commit | 2fb66caca2c9e69c6a0584060114fcd52e59d5ff (patch) | |
tree | de895acfd51886da7e4ca547baea0b45e954c72e | |
parent | 267e28bb75e97755ab3bbe128b75623734f2b3fd (diff) |
- djm@cvs.openbsd.org 2008/06/12 03:40:52
[clientloop.h mux.c channels.c clientloop.c channels.h]
Enable ~ escapes for multiplex slave sessions; give each channel
its own escape state and hook the escape filters up to muxed
channels. bz #1331
Mux slaves do not currently support the ~^Z and ~& escapes.
NB. this change cranks the mux protocol version, so a new ssh
mux client will not be able to connect to a running old ssh
mux master.
ok dtucker@
-rw-r--r-- | ChangeLog | 12 | ||||
-rw-r--r-- | channels.c | 5 | ||||
-rw-r--r-- | channels.h | 5 | ||||
-rw-r--r-- | clientloop.c | 154 | ||||
-rw-r--r-- | clientloop.h | 22 | ||||
-rw-r--r-- | mux.c | 93 |
6 files changed, 202 insertions, 89 deletions
@@ -68,6 +68,16 @@ | |||
68 | [key.c] | 68 | [key.c] |
69 | use an odd number of rows and columns and a separate start marker, looks | 69 | use an odd number of rows and columns and a separate start marker, looks |
70 | better; ok grunk@ | 70 | better; ok grunk@ |
71 | - djm@cvs.openbsd.org 2008/06/12 03:40:52 | ||
72 | [clientloop.h mux.c channels.c clientloop.c channels.h] | ||
73 | Enable ~ escapes for multiplex slave sessions; give each channel | ||
74 | its own escape state and hook the escape filters up to muxed | ||
75 | channels. bz #1331 | ||
76 | Mux slaves do not currently support the ~^Z and ~& escapes. | ||
77 | NB. this change cranks the mux protocol version, so a new ssh | ||
78 | mux client will not be able to connect to a running old ssh | ||
79 | mux master. | ||
80 | ok dtucker@ | ||
71 | 81 | ||
72 | 20080611 | 82 | 20080611 |
73 | - (djm) [channels.c configure.ac] | 83 | - (djm) [channels.c configure.ac] |
@@ -4230,4 +4240,4 @@ | |||
4230 | OpenServer 6 and add osr5bigcrypt support so when someone migrates | 4240 | OpenServer 6 and add osr5bigcrypt support so when someone migrates |
4231 | passwords between UnixWare and OpenServer they will still work. OK dtucker@ | 4241 | passwords between UnixWare and OpenServer they will still work. OK dtucker@ |
4232 | 4242 | ||
4233 | $Id: ChangeLog,v 1.4976 2008/06/12 18:48:11 dtucker Exp $ | 4243 | $Id: ChangeLog,v 1.4977 2008/06/12 18:49:33 dtucker Exp $ |
diff --git a/channels.c b/channels.c index 233c2247b..c539990f6 100644 --- a/channels.c +++ b/channels.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: channels.c,v 1.278 2008/06/10 04:50:25 dtucker Exp $ */ | 1 | /* $OpenBSD: channels.c,v 1.279 2008/06/12 03:40:52 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 |
@@ -731,7 +731,7 @@ channel_cancel_cleanup(int id) | |||
731 | 731 | ||
732 | void | 732 | void |
733 | channel_register_filter(int id, channel_infilter_fn *ifn, | 733 | channel_register_filter(int id, channel_infilter_fn *ifn, |
734 | channel_outfilter_fn *ofn) | 734 | channel_outfilter_fn *ofn, void *ctx) |
735 | { | 735 | { |
736 | Channel *c = channel_lookup(id); | 736 | Channel *c = channel_lookup(id); |
737 | 737 | ||
@@ -741,6 +741,7 @@ channel_register_filter(int id, channel_infilter_fn *ifn, | |||
741 | } | 741 | } |
742 | c->input_filter = ifn; | 742 | c->input_filter = ifn; |
743 | c->output_filter = ofn; | 743 | c->output_filter = ofn; |
744 | c->filter_ctx = ctx; | ||
744 | } | 745 | } |
745 | 746 | ||
746 | void | 747 | void |
diff --git a/channels.h b/channels.h index dc1f483ed..450321d43 100644 --- a/channels.h +++ b/channels.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: channels.h,v 1.93 2008/06/10 04:50:25 dtucker Exp $ */ | 1 | /* $OpenBSD: channels.h,v 1.94 2008/06/12 03:40:52 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
@@ -131,6 +131,7 @@ struct Channel { | |||
131 | /* filter */ | 131 | /* filter */ |
132 | channel_infilter_fn *input_filter; | 132 | channel_infilter_fn *input_filter; |
133 | channel_outfilter_fn *output_filter; | 133 | channel_outfilter_fn *output_filter; |
134 | void *filter_ctx; | ||
134 | 135 | ||
135 | /* keep boundaries */ | 136 | /* keep boundaries */ |
136 | int datagram; | 137 | int datagram; |
@@ -195,7 +196,7 @@ void channel_request_start(int, char *, int); | |||
195 | void channel_register_cleanup(int, channel_callback_fn *, int); | 196 | void channel_register_cleanup(int, channel_callback_fn *, int); |
196 | void channel_register_open_confirm(int, channel_callback_fn *, void *); | 197 | void channel_register_open_confirm(int, channel_callback_fn *, void *); |
197 | void channel_register_filter(int, channel_infilter_fn *, | 198 | void channel_register_filter(int, channel_infilter_fn *, |
198 | channel_outfilter_fn *); | 199 | channel_outfilter_fn *, void *); |
199 | void channel_register_status_confirm(int, channel_confirm_cb *, | 200 | void channel_register_status_confirm(int, channel_confirm_cb *, |
200 | channel_confirm_abandon_cb *, void *); | 201 | channel_confirm_abandon_cb *, void *); |
201 | void channel_cancel_cleanup(int); | 202 | void channel_cancel_cleanup(int); |
diff --git a/clientloop.c b/clientloop.c index 3bc8bb8d0..b45e7298a 100644 --- a/clientloop.c +++ b/clientloop.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: clientloop.c,v 1.194 2008/05/19 20:53:52 djm Exp $ */ | 1 | /* $OpenBSD: clientloop.c,v 1.195 2008/06/12 03:40:52 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 |
@@ -144,8 +144,8 @@ static int in_non_blocking_mode = 0; | |||
144 | 144 | ||
145 | /* Common data for the client loop code. */ | 145 | /* Common data for the client loop code. */ |
146 | static volatile sig_atomic_t quit_pending; /* Set non-zero to quit the loop. */ | 146 | static volatile sig_atomic_t quit_pending; /* Set non-zero to quit the loop. */ |
147 | static int escape_char; /* Escape character. */ | 147 | static int escape_char1; /* Escape character. (proto1 only) */ |
148 | static int escape_pending; /* Last character was the escape character */ | 148 | static int escape_pending1; /* Last character was an escape (proto1 only) */ |
149 | static int last_was_cr; /* Last character was a newline. */ | 149 | static int last_was_cr; /* Last character was a newline. */ |
150 | static int exit_status; /* Used to store the exit status of the command. */ | 150 | static int exit_status; /* Used to store the exit status of the command. */ |
151 | static int stdin_eof; /* EOF has been encountered on standard error. */ | 151 | static int stdin_eof; /* EOF has been encountered on standard error. */ |
@@ -162,6 +162,13 @@ static int session_closed = 0; /* In SSH2: login session closed. */ | |||
162 | static void client_init_dispatch(void); | 162 | static void client_init_dispatch(void); |
163 | int session_ident = -1; | 163 | int session_ident = -1; |
164 | 164 | ||
165 | /* Track escape per proto2 channel */ | ||
166 | struct escape_filter_ctx { | ||
167 | int escape_pending; | ||
168 | int escape_char; | ||
169 | }; | ||
170 | |||
171 | /* Context for channel confirmation replies */ | ||
165 | struct channel_reply_ctx { | 172 | struct channel_reply_ctx { |
166 | const char *request_type; | 173 | const char *request_type; |
167 | int id, do_close; | 174 | int id, do_close; |
@@ -385,8 +392,8 @@ client_check_initial_eof_on_stdin(void) | |||
385 | * and also process it as an escape character if | 392 | * and also process it as an escape character if |
386 | * appropriate. | 393 | * appropriate. |
387 | */ | 394 | */ |
388 | if ((u_char) buf[0] == escape_char) | 395 | if ((u_char) buf[0] == escape_char1) |
389 | escape_pending = 1; | 396 | escape_pending1 = 1; |
390 | else | 397 | else |
391 | buffer_append(&stdin_buffer, buf, 1); | 398 | buffer_append(&stdin_buffer, buf, 1); |
392 | } | 399 | } |
@@ -813,9 +820,12 @@ out: | |||
813 | xfree(fwd.connect_host); | 820 | xfree(fwd.connect_host); |
814 | } | 821 | } |
815 | 822 | ||
816 | /* process the characters one by one */ | 823 | /* |
824 | * Process the characters one by one, call with c==NULL for proto1 case. | ||
825 | */ | ||
817 | static int | 826 | static int |
818 | process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len) | 827 | process_escapes(Channel *c, Buffer *bin, Buffer *bout, Buffer *berr, |
828 | char *buf, int len) | ||
819 | { | 829 | { |
820 | char string[1024]; | 830 | char string[1024]; |
821 | pid_t pid; | 831 | pid_t pid; |
@@ -823,7 +833,20 @@ process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len) | |||
823 | u_int i; | 833 | u_int i; |
824 | u_char ch; | 834 | u_char ch; |
825 | char *s; | 835 | char *s; |
836 | int *escape_pendingp, escape_char; | ||
837 | struct escape_filter_ctx *efc; | ||
826 | 838 | ||
839 | if (c == NULL) { | ||
840 | escape_pendingp = &escape_pending1; | ||
841 | escape_char = escape_char1; | ||
842 | } else { | ||
843 | if (c->filter_ctx == NULL) | ||
844 | return 0; | ||
845 | efc = (struct escape_filter_ctx *)c->filter_ctx; | ||
846 | escape_pendingp = &efc->escape_pending; | ||
847 | escape_char = efc->escape_char; | ||
848 | } | ||
849 | |||
827 | if (len <= 0) | 850 | if (len <= 0) |
828 | return (0); | 851 | return (0); |
829 | 852 | ||
@@ -831,25 +854,43 @@ process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len) | |||
831 | /* Get one character at a time. */ | 854 | /* Get one character at a time. */ |
832 | ch = buf[i]; | 855 | ch = buf[i]; |
833 | 856 | ||
834 | if (escape_pending) { | 857 | if (*escape_pendingp) { |
835 | /* We have previously seen an escape character. */ | 858 | /* We have previously seen an escape character. */ |
836 | /* Clear the flag now. */ | 859 | /* Clear the flag now. */ |
837 | escape_pending = 0; | 860 | *escape_pendingp = 0; |
838 | 861 | ||
839 | /* Process the escaped character. */ | 862 | /* Process the escaped character. */ |
840 | switch (ch) { | 863 | switch (ch) { |
841 | case '.': | 864 | case '.': |
842 | /* Terminate the connection. */ | 865 | /* Terminate the connection. */ |
843 | snprintf(string, sizeof string, "%c.\r\n", escape_char); | 866 | snprintf(string, sizeof string, "%c.\r\n", |
867 | escape_char); | ||
844 | buffer_append(berr, string, strlen(string)); | 868 | buffer_append(berr, string, strlen(string)); |
845 | 869 | ||
846 | quit_pending = 1; | 870 | if (c && c->ctl_fd != -1) { |
871 | chan_read_failed(c); | ||
872 | chan_write_failed(c); | ||
873 | return 0; | ||
874 | } else | ||
875 | quit_pending = 1; | ||
847 | return -1; | 876 | return -1; |
848 | 877 | ||
849 | case 'Z' - 64: | 878 | case 'Z' - 64: |
879 | /* XXX support this for mux clients */ | ||
880 | if (c && c->ctl_fd != -1) { | ||
881 | noescape: | ||
882 | snprintf(string, sizeof string, | ||
883 | "%c%c escape not available to " | ||
884 | "multiplexed sessions\r\n", | ||
885 | escape_char, ch); | ||
886 | buffer_append(berr, string, | ||
887 | strlen(string)); | ||
888 | continue; | ||
889 | } | ||
850 | /* Suspend the program. */ | 890 | /* Suspend the program. */ |
851 | /* Print a message to that effect to the user. */ | 891 | /* Print a message to that effect to the user. */ |
852 | snprintf(string, sizeof string, "%c^Z [suspend ssh]\r\n", escape_char); | 892 | snprintf(string, sizeof string, |
893 | "%c^Z [suspend ssh]\r\n", escape_char); | ||
853 | buffer_append(berr, string, strlen(string)); | 894 | buffer_append(berr, string, strlen(string)); |
854 | 895 | ||
855 | /* Restore terminal modes and suspend. */ | 896 | /* Restore terminal modes and suspend. */ |
@@ -881,6 +922,8 @@ process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len) | |||
881 | continue; | 922 | continue; |
882 | 923 | ||
883 | case '&': | 924 | case '&': |
925 | if (c && c->ctl_fd != -1) | ||
926 | goto noescape; | ||
884 | /* | 927 | /* |
885 | * Detach the program (continue to serve connections, | 928 | * Detach the program (continue to serve connections, |
886 | * but put in background and no more new connections). | 929 | * but put in background and no more new connections). |
@@ -929,27 +972,50 @@ process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len) | |||
929 | continue; | 972 | continue; |
930 | 973 | ||
931 | case '?': | 974 | case '?': |
932 | snprintf(string, sizeof string, | 975 | if (c && c->ctl_fd != -1) { |
976 | snprintf(string, sizeof string, | ||
933 | "%c?\r\n\ | 977 | "%c?\r\n\ |
934 | Supported escape sequences:\r\n\ | 978 | Supported escape sequences:\r\n\ |
935 | %c. - terminate connection\r\n\ | 979 | %c. - terminate session\r\n\ |
936 | %cB - send a BREAK to the remote system\r\n\ | 980 | %cB - send a BREAK to the remote system\r\n\ |
937 | %cC - open a command line\r\n\ | 981 | %cC - open a command line\r\n\ |
938 | %cR - Request rekey (SSH protocol 2 only)\r\n\ | 982 | %cR - Request rekey (SSH protocol 2 only)\r\n\ |
939 | %c^Z - suspend ssh\r\n\ | 983 | %c# - list forwarded connections\r\n\ |
940 | %c# - list forwarded connections\r\n\ | 984 | %c? - this message\r\n\ |
941 | %c& - background ssh (when waiting for connections to terminate)\r\n\ | 985 | %c%c - send the escape character by typing it twice\r\n\ |
942 | %c? - this message\r\n\ | ||
943 | %c%c - send the escape character by typing it twice\r\n\ | ||
944 | (Note that escapes are only recognized immediately after newline.)\r\n", | 986 | (Note that escapes are only recognized immediately after newline.)\r\n", |
945 | escape_char, escape_char, escape_char, escape_char, | 987 | escape_char, escape_char, |
946 | escape_char, escape_char, escape_char, escape_char, | 988 | escape_char, escape_char, |
947 | escape_char, escape_char, escape_char); | 989 | escape_char, escape_char, |
990 | escape_char, escape_char, | ||
991 | escape_char); | ||
992 | } else { | ||
993 | snprintf(string, sizeof string, | ||
994 | "%c?\r\n\ | ||
995 | Supported escape sequences:\r\n\ | ||
996 | %c. - terminate connection (and any multiplexed sessions)\r\n\ | ||
997 | %cB - send a BREAK to the remote system\r\n\ | ||
998 | %cC - open a command line\r\n\ | ||
999 | %cR - Request rekey (SSH protocol 2 only)\r\n\ | ||
1000 | %c^Z - suspend ssh\r\n\ | ||
1001 | %c# - list forwarded connections\r\n\ | ||
1002 | %c& - background ssh (when waiting for connections to terminate)\r\n\ | ||
1003 | %c? - this message\r\n\ | ||
1004 | %c%c - send the escape character by typing it twice\r\n\ | ||
1005 | (Note that escapes are only recognized immediately after newline.)\r\n", | ||
1006 | escape_char, escape_char, | ||
1007 | escape_char, escape_char, | ||
1008 | escape_char, escape_char, | ||
1009 | escape_char, escape_char, | ||
1010 | escape_char, escape_char, | ||
1011 | escape_char); | ||
1012 | } | ||
948 | buffer_append(berr, string, strlen(string)); | 1013 | buffer_append(berr, string, strlen(string)); |
949 | continue; | 1014 | continue; |
950 | 1015 | ||
951 | case '#': | 1016 | case '#': |
952 | snprintf(string, sizeof string, "%c#\r\n", escape_char); | 1017 | snprintf(string, sizeof string, "%c#\r\n", |
1018 | escape_char); | ||
953 | buffer_append(berr, string, strlen(string)); | 1019 | buffer_append(berr, string, strlen(string)); |
954 | s = channel_open_message(); | 1020 | s = channel_open_message(); |
955 | buffer_append(berr, s, strlen(s)); | 1021 | buffer_append(berr, s, strlen(s)); |
@@ -975,7 +1041,7 @@ Supported escape sequences:\r\n\ | |||
975 | */ | 1041 | */ |
976 | if (last_was_cr && ch == escape_char) { | 1042 | if (last_was_cr && ch == escape_char) { |
977 | /* It is. Set the flag and continue to next character. */ | 1043 | /* It is. Set the flag and continue to next character. */ |
978 | escape_pending = 1; | 1044 | *escape_pendingp = 1; |
979 | continue; | 1045 | continue; |
980 | } | 1046 | } |
981 | } | 1047 | } |
@@ -1026,7 +1092,7 @@ client_process_input(fd_set *readset) | |||
1026 | packet_start(SSH_CMSG_EOF); | 1092 | packet_start(SSH_CMSG_EOF); |
1027 | packet_send(); | 1093 | packet_send(); |
1028 | } | 1094 | } |
1029 | } else if (escape_char == SSH_ESCAPECHAR_NONE) { | 1095 | } else if (escape_char1 == SSH_ESCAPECHAR_NONE) { |
1030 | /* | 1096 | /* |
1031 | * Normal successful read, and no escape character. | 1097 | * Normal successful read, and no escape character. |
1032 | * Just append the data to buffer. | 1098 | * Just append the data to buffer. |
@@ -1037,8 +1103,8 @@ client_process_input(fd_set *readset) | |||
1037 | * Normal, successful read. But we have an escape character | 1103 | * Normal, successful read. But we have an escape character |
1038 | * and have to process the characters one by one. | 1104 | * and have to process the characters one by one. |
1039 | */ | 1105 | */ |
1040 | if (process_escapes(&stdin_buffer, &stdout_buffer, | 1106 | if (process_escapes(NULL, &stdin_buffer, |
1041 | &stderr_buffer, buf, len) == -1) | 1107 | &stdout_buffer, &stderr_buffer, buf, len) == -1) |
1042 | return; | 1108 | return; |
1043 | } | 1109 | } |
1044 | } | 1110 | } |
@@ -1113,13 +1179,26 @@ client_process_buffered_input_packets(void) | |||
1113 | 1179 | ||
1114 | /* scan buf[] for '~' before sending data to the peer */ | 1180 | /* scan buf[] for '~' before sending data to the peer */ |
1115 | 1181 | ||
1116 | static int | 1182 | /* Helper: allocate a new escape_filter_ctx and fill in its escape char */ |
1117 | simple_escape_filter(Channel *c, char *buf, int len) | 1183 | void * |
1184 | client_new_escape_filter_ctx(int escape_char) | ||
1185 | { | ||
1186 | struct escape_filter_ctx *ret; | ||
1187 | |||
1188 | ret = xmalloc(sizeof(*ret)); | ||
1189 | ret->escape_pending = 0; | ||
1190 | ret->escape_char = escape_char; | ||
1191 | return (void *)ret; | ||
1192 | } | ||
1193 | |||
1194 | int | ||
1195 | client_simple_escape_filter(Channel *c, char *buf, int len) | ||
1118 | { | 1196 | { |
1119 | if (c->extended_usage != CHAN_EXTENDED_WRITE) | 1197 | if (c->extended_usage != CHAN_EXTENDED_WRITE) |
1120 | return 0; | 1198 | return 0; |
1121 | 1199 | ||
1122 | return process_escapes(&c->input, &c->output, &c->extended, buf, len); | 1200 | return process_escapes(c, &c->input, &c->output, &c->extended, |
1201 | buf, len); | ||
1123 | } | 1202 | } |
1124 | 1203 | ||
1125 | static void | 1204 | static void |
@@ -1151,7 +1230,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1151 | start_time = get_current_time(); | 1230 | start_time = get_current_time(); |
1152 | 1231 | ||
1153 | /* Initialize variables. */ | 1232 | /* Initialize variables. */ |
1154 | escape_pending = 0; | 1233 | escape_pending1 = 0; |
1155 | last_was_cr = 1; | 1234 | last_was_cr = 1; |
1156 | exit_status = -1; | 1235 | exit_status = -1; |
1157 | stdin_eof = 0; | 1236 | stdin_eof = 0; |
@@ -1178,7 +1257,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1178 | stdout_bytes = 0; | 1257 | stdout_bytes = 0; |
1179 | stderr_bytes = 0; | 1258 | stderr_bytes = 0; |
1180 | quit_pending = 0; | 1259 | quit_pending = 0; |
1181 | escape_char = escape_char_arg; | 1260 | escape_char1 = escape_char_arg; |
1182 | 1261 | ||
1183 | /* Initialize buffers. */ | 1262 | /* Initialize buffers. */ |
1184 | buffer_init(&stdin_buffer); | 1263 | buffer_init(&stdin_buffer); |
@@ -1206,9 +1285,10 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1206 | 1285 | ||
1207 | if (compat20) { | 1286 | if (compat20) { |
1208 | session_ident = ssh2_chan_id; | 1287 | session_ident = ssh2_chan_id; |
1209 | if (escape_char != SSH_ESCAPECHAR_NONE) | 1288 | if (escape_char_arg != SSH_ESCAPECHAR_NONE) |
1210 | channel_register_filter(session_ident, | 1289 | channel_register_filter(session_ident, |
1211 | simple_escape_filter, NULL); | 1290 | client_simple_escape_filter, NULL, |
1291 | client_new_escape_filter_ctx(escape_char_arg)); | ||
1212 | if (session_ident != -1) | 1292 | if (session_ident != -1) |
1213 | channel_register_cleanup(session_ident, | 1293 | channel_register_cleanup(session_ident, |
1214 | client_channel_closed, 0); | 1294 | client_channel_closed, 0); |
diff --git a/clientloop.h b/clientloop.h index 6f8e70123..cecbfb1a8 100644 --- a/clientloop.h +++ b/clientloop.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: clientloop.h,v 1.19 2008/05/09 14:18:44 djm Exp $ */ | 1 | /* $OpenBSD: clientloop.h,v 1.20 2008/06/12 03:40:52 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
@@ -46,8 +46,12 @@ void client_session2_setup(int, int, int, const char *, struct termios *, | |||
46 | int, Buffer *, char **); | 46 | int, Buffer *, char **); |
47 | int client_request_tun_fwd(int, int, int); | 47 | int client_request_tun_fwd(int, int, int); |
48 | 48 | ||
49 | /* Escape filter for protocol 2 sessions */ | ||
50 | void *client_new_escape_filter_ctx(int); | ||
51 | int client_simple_escape_filter(Channel *, char *, int); | ||
52 | |||
49 | /* Multiplexing protocol version */ | 53 | /* Multiplexing protocol version */ |
50 | #define SSHMUX_VER 1 | 54 | #define SSHMUX_VER 2 |
51 | 55 | ||
52 | /* Multiplexing control protocol flags */ | 56 | /* Multiplexing control protocol flags */ |
53 | #define SSHMUX_COMMAND_OPEN 1 /* Open new connection */ | 57 | #define SSHMUX_COMMAND_OPEN 1 /* Open new connection */ |
@@ -59,20 +63,6 @@ int client_request_tun_fwd(int, int, int); | |||
59 | #define SSHMUX_FLAG_X11_FWD (1<<2) /* Request X11 forwarding */ | 63 | #define SSHMUX_FLAG_X11_FWD (1<<2) /* Request X11 forwarding */ |
60 | #define SSHMUX_FLAG_AGENT_FWD (1<<3) /* Request agent forwarding */ | 64 | #define SSHMUX_FLAG_AGENT_FWD (1<<3) /* Request agent forwarding */ |
61 | 65 | ||
62 | /* Multiplexing routines */ | ||
63 | |||
64 | struct mux_session_confirm_ctx { | ||
65 | int want_tty; | ||
66 | int want_subsys; | ||
67 | int want_x_fwd; | ||
68 | int want_agent_fwd; | ||
69 | Buffer cmd; | ||
70 | char *term; | ||
71 | struct termios tio; | ||
72 | char **env; | ||
73 | }; | ||
74 | |||
75 | /* mux.c */ | ||
76 | void muxserver_listen(void); | 66 | void muxserver_listen(void); |
77 | int muxserver_accept_control(void); | 67 | int muxserver_accept_control(void); |
78 | void muxclient(const char *); | 68 | void muxclient(const char *); |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: mux.c,v 1.1 2008/05/09 14:18:44 djm Exp $ */ | 1 | /* $OpenBSD: mux.c,v 1.2 2008/06/12 03:40:52 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 | * |
@@ -19,6 +19,20 @@ | |||
19 | 19 | ||
20 | #include "includes.h" | 20 | #include "includes.h" |
21 | 21 | ||
22 | /* | ||
23 | * TODO: | ||
24 | * 1. partial reads in muxserver_accept_control (maybe make channels | ||
25 | * from accepted connections) | ||
26 | * 2. Better signalling from master to slave, especially passing of | ||
27 | * error messages | ||
28 | * 3. Better fall-back from mux slave error to new connection. | ||
29 | * 3. Add/delete forwardings via slave | ||
30 | * 4. ExitOnForwardingFailure (after #3 obviously) | ||
31 | * 5. Maybe extension mechanisms for multi-X11/multi-agent forwarding | ||
32 | * 6. Document the mux mini-protocol somewhere. | ||
33 | * 6. Support ~^Z in mux slaves. | ||
34 | */ | ||
35 | |||
22 | #include <sys/types.h> | 36 | #include <sys/types.h> |
23 | #include <sys/param.h> | 37 | #include <sys/param.h> |
24 | #include <sys/stat.h> | 38 | #include <sys/stat.h> |
@@ -71,6 +85,18 @@ extern char *host; | |||
71 | int subsystem_flag; | 85 | int subsystem_flag; |
72 | extern Buffer command; | 86 | extern Buffer command; |
73 | 87 | ||
88 | /* Context for session open confirmation callback */ | ||
89 | struct mux_session_confirm_ctx { | ||
90 | int want_tty; | ||
91 | int want_subsys; | ||
92 | int want_x_fwd; | ||
93 | int want_agent_fwd; | ||
94 | Buffer cmd; | ||
95 | char *term; | ||
96 | struct termios tio; | ||
97 | char **env; | ||
98 | }; | ||
99 | |||
74 | /* fd to control socket */ | 100 | /* fd to control socket */ |
75 | int muxserver_sock = -1; | 101 | int muxserver_sock = -1; |
76 | 102 | ||
@@ -131,7 +157,7 @@ muxserver_listen(void) | |||
131 | 157 | ||
132 | /* Callback on open confirmation in mux master for a mux client session. */ | 158 | /* Callback on open confirmation in mux master for a mux client session. */ |
133 | static void | 159 | static void |
134 | client_extra_session2_setup(int id, void *arg) | 160 | mux_session_confirm(int id, void *arg) |
135 | { | 161 | { |
136 | struct mux_session_confirm_ctx *cctx = arg; | 162 | struct mux_session_confirm_ctx *cctx = arg; |
137 | const char *display; | 163 | const char *display; |
@@ -190,7 +216,7 @@ muxserver_accept_control(void) | |||
190 | struct sockaddr_storage addr; | 216 | struct sockaddr_storage addr; |
191 | struct mux_session_confirm_ctx *cctx; | 217 | struct mux_session_confirm_ctx *cctx; |
192 | char *cmd; | 218 | char *cmd; |
193 | u_int i, j, len, env_len, mux_command, flags; | 219 | u_int i, j, len, env_len, mux_command, flags, escape_char; |
194 | uid_t euid; | 220 | uid_t euid; |
195 | gid_t egid; | 221 | gid_t egid; |
196 | int start_close = 0; | 222 | int start_close = 0; |
@@ -317,6 +343,7 @@ muxserver_accept_control(void) | |||
317 | cctx->want_x_fwd = (flags & SSHMUX_FLAG_X11_FWD) != 0; | 343 | cctx->want_x_fwd = (flags & SSHMUX_FLAG_X11_FWD) != 0; |
318 | cctx->want_agent_fwd = (flags & SSHMUX_FLAG_AGENT_FWD) != 0; | 344 | cctx->want_agent_fwd = (flags & SSHMUX_FLAG_AGENT_FWD) != 0; |
319 | cctx->term = buffer_get_string(&m, &len); | 345 | cctx->term = buffer_get_string(&m, &len); |
346 | escape_char = buffer_get_int(&m); | ||
320 | 347 | ||
321 | cmd = buffer_get_string(&m, &len); | 348 | cmd = buffer_get_string(&m, &len); |
322 | buffer_init(&cctx->cmd); | 349 | buffer_init(&cctx->cmd); |
@@ -402,14 +429,17 @@ muxserver_accept_control(void) | |||
402 | new_fd[0], new_fd[1], new_fd[2], window, packetmax, | 429 | new_fd[0], new_fd[1], new_fd[2], window, packetmax, |
403 | CHAN_EXTENDED_WRITE, "client-session", /*nonblock*/0); | 430 | CHAN_EXTENDED_WRITE, "client-session", /*nonblock*/0); |
404 | 431 | ||
405 | /* XXX */ | ||
406 | c->ctl_fd = client_fd; | 432 | c->ctl_fd = client_fd; |
433 | if (cctx->want_tty && escape_char != 0xffffffff) { | ||
434 | channel_register_filter(c->self, | ||
435 | client_simple_escape_filter, NULL, | ||
436 | client_new_escape_filter_ctx((int)escape_char)); | ||
437 | } | ||
407 | 438 | ||
408 | debug3("%s: channel_new: %d", __func__, c->self); | 439 | debug3("%s: channel_new: %d", __func__, c->self); |
409 | 440 | ||
410 | channel_send_open(c->self); | 441 | channel_send_open(c->self); |
411 | channel_register_open_confirm(c->self, | 442 | channel_register_open_confirm(c->self, mux_session_confirm, cctx); |
412 | client_extra_session2_setup, cctx); | ||
413 | return 0; | 443 | return 0; |
414 | } | 444 | } |
415 | 445 | ||
@@ -561,33 +591,34 @@ muxclient(const char *path) | |||
561 | fprintf(stderr, "Exit request sent.\r\n"); | 591 | fprintf(stderr, "Exit request sent.\r\n"); |
562 | exit(0); | 592 | exit(0); |
563 | case SSHMUX_COMMAND_OPEN: | 593 | case SSHMUX_COMMAND_OPEN: |
564 | /* continue below */ | 594 | buffer_put_cstring(&m, term ? term : ""); |
595 | if (options.escape_char == SSH_ESCAPECHAR_NONE) | ||
596 | buffer_put_int(&m, 0xffffffff); | ||
597 | else | ||
598 | buffer_put_int(&m, options.escape_char); | ||
599 | buffer_append(&command, "\0", 1); | ||
600 | buffer_put_cstring(&m, buffer_ptr(&command)); | ||
601 | |||
602 | if (options.num_send_env == 0 || environ == NULL) { | ||
603 | buffer_put_int(&m, 0); | ||
604 | } else { | ||
605 | /* Pass environment */ | ||
606 | num_env = 0; | ||
607 | for (i = 0; environ[i] != NULL; i++) { | ||
608 | if (env_permitted(environ[i])) | ||
609 | num_env++; /* Count */ | ||
610 | } | ||
611 | buffer_put_int(&m, num_env); | ||
612 | for (i = 0; environ[i] != NULL && num_env >= 0; i++) { | ||
613 | if (env_permitted(environ[i])) { | ||
614 | num_env--; | ||
615 | buffer_put_cstring(&m, environ[i]); | ||
616 | } | ||
617 | } | ||
618 | } | ||
565 | break; | 619 | break; |
566 | default: | 620 | default: |
567 | fatal("silly muxclient_command %d", muxclient_command); | 621 | fatal("unrecognised muxclient_command %d", muxclient_command); |
568 | } | ||
569 | |||
570 | /* SSHMUX_COMMAND_OPEN */ | ||
571 | buffer_put_cstring(&m, term ? term : ""); | ||
572 | buffer_append(&command, "\0", 1); | ||
573 | buffer_put_cstring(&m, buffer_ptr(&command)); | ||
574 | |||
575 | if (options.num_send_env == 0 || environ == NULL) { | ||
576 | buffer_put_int(&m, 0); | ||
577 | } else { | ||
578 | /* Pass environment */ | ||
579 | num_env = 0; | ||
580 | for (i = 0; environ[i] != NULL; i++) | ||
581 | if (env_permitted(environ[i])) | ||
582 | num_env++; /* Count */ | ||
583 | |||
584 | buffer_put_int(&m, num_env); | ||
585 | |||
586 | for (i = 0; environ[i] != NULL && num_env >= 0; i++) | ||
587 | if (env_permitted(environ[i])) { | ||
588 | num_env--; | ||
589 | buffer_put_cstring(&m, environ[i]); | ||
590 | } | ||
591 | } | 622 | } |
592 | 623 | ||
593 | if (ssh_msg_send(sock, SSHMUX_VER, &m) == -1) | 624 | if (ssh_msg_send(sock, SSHMUX_VER, &m) == -1) |