|
Lines 136-143
static int in_non_blocking_mode = 0;
Link Here
|
| 136 |
|
136 |
|
| 137 |
/* Common data for the client loop code. */ |
137 |
/* Common data for the client loop code. */ |
| 138 |
static volatile sig_atomic_t quit_pending; /* Set non-zero to quit the loop. */ |
138 |
static volatile sig_atomic_t quit_pending; /* Set non-zero to quit the loop. */ |
| 139 |
static int escape_char; /* Escape character. */ |
139 |
static int escape_char1; /* Escape character. (proto1 only) */ |
| 140 |
static int escape_pending; /* Last character was the escape character */ |
140 |
static int escape_pending1; /* Last character was an escape (proto1 only) */ |
| 141 |
static int last_was_cr; /* Last character was a newline. */ |
141 |
static int last_was_cr; /* Last character was a newline. */ |
| 142 |
static int exit_status; /* Used to store the exit status of the command. */ |
142 |
static int exit_status; /* Used to store the exit status of the command. */ |
| 143 |
static int stdin_eof; /* EOF has been encountered on standard error. */ |
143 |
static int stdin_eof; /* EOF has been encountered on standard error. */ |
|
Lines 154-159
static int session_closed = 0; /* In SSH
Link Here
|
| 154 |
static void client_init_dispatch(void); |
154 |
static void client_init_dispatch(void); |
| 155 |
int session_ident = -1; |
155 |
int session_ident = -1; |
| 156 |
|
156 |
|
|
|
157 |
/* Track escape per proto2 channel */ |
| 158 |
struct escape_filter_ctx { |
| 159 |
int escape_pending; |
| 160 |
int escape_char; |
| 161 |
}; |
| 162 |
|
| 163 |
/* Context for channel confirmation replies */ |
| 157 |
struct channel_reply_ctx { |
164 |
struct channel_reply_ctx { |
| 158 |
const char *request_type; |
165 |
const char *request_type; |
| 159 |
int id, do_close; |
166 |
int id, do_close; |
|
Lines 377-384
client_check_initial_eof_on_stdin(void)
Link Here
|
| 377 |
* and also process it as an escape character if |
384 |
* and also process it as an escape character if |
| 378 |
* appropriate. |
385 |
* appropriate. |
| 379 |
*/ |
386 |
*/ |
| 380 |
if ((u_char) buf[0] == escape_char) |
387 |
if ((u_char) buf[0] == escape_char1) |
| 381 |
escape_pending = 1; |
388 |
escape_pending1 = 1; |
| 382 |
else |
389 |
else |
| 383 |
buffer_append(&stdin_buffer, buf, 1); |
390 |
buffer_append(&stdin_buffer, buf, 1); |
| 384 |
} |
391 |
} |
|
Lines 805-813
out:
Link Here
|
| 805 |
xfree(fwd.connect_host); |
812 |
xfree(fwd.connect_host); |
| 806 |
} |
813 |
} |
| 807 |
|
814 |
|
| 808 |
/* process the characters one by one */ |
815 |
/* |
|
|
816 |
* Process the characters one by one, call with c==NULL for proto1 case. |
| 817 |
*/ |
| 809 |
static int |
818 |
static int |
| 810 |
process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len) |
819 |
process_escapes(Channel *c, Buffer *bin, Buffer *bout, Buffer *berr, |
|
|
820 |
char *buf, int len) |
| 811 |
{ |
821 |
{ |
| 812 |
char string[1024]; |
822 |
char string[1024]; |
| 813 |
pid_t pid; |
823 |
pid_t pid; |
|
Lines 815-821
process_escapes(Buffer *bin, Buffer *bou
Link Here
|
| 815 |
u_int i; |
825 |
u_int i; |
| 816 |
u_char ch; |
826 |
u_char ch; |
| 817 |
char *s; |
827 |
char *s; |
|
|
828 |
int *escape_pendingp, escape_char; |
| 829 |
struct escape_filter_ctx *efc; |
| 818 |
|
830 |
|
|
|
831 |
if (c == NULL) { |
| 832 |
escape_pendingp = &escape_pending1; |
| 833 |
escape_char = escape_char1; |
| 834 |
} else { |
| 835 |
if (c->filter_ctx == NULL) |
| 836 |
return 0; |
| 837 |
efc = (struct escape_filter_ctx *)c->filter_ctx; |
| 838 |
escape_pendingp = &efc->escape_pending; |
| 839 |
escape_char = efc->escape_char; |
| 840 |
} |
| 841 |
|
| 819 |
if (len <= 0) |
842 |
if (len <= 0) |
| 820 |
return (0); |
843 |
return (0); |
| 821 |
|
844 |
|
|
Lines 823-847
process_escapes(Buffer *bin, Buffer *bou
Link Here
|
| 823 |
/* Get one character at a time. */ |
846 |
/* Get one character at a time. */ |
| 824 |
ch = buf[i]; |
847 |
ch = buf[i]; |
| 825 |
|
848 |
|
| 826 |
if (escape_pending) { |
849 |
if (*escape_pendingp) { |
| 827 |
/* We have previously seen an escape character. */ |
850 |
/* We have previously seen an escape character. */ |
| 828 |
/* Clear the flag now. */ |
851 |
/* Clear the flag now. */ |
| 829 |
escape_pending = 0; |
852 |
*escape_pendingp = 0; |
| 830 |
|
853 |
|
| 831 |
/* Process the escaped character. */ |
854 |
/* Process the escaped character. */ |
| 832 |
switch (ch) { |
855 |
switch (ch) { |
| 833 |
case '.': |
856 |
case '.': |
| 834 |
/* Terminate the connection. */ |
857 |
/* Terminate the connection. */ |
| 835 |
snprintf(string, sizeof string, "%c.\r\n", escape_char); |
858 |
snprintf(string, sizeof string, "%c.\r\n", |
|
|
859 |
escape_char); |
| 836 |
buffer_append(berr, string, strlen(string)); |
860 |
buffer_append(berr, string, strlen(string)); |
| 837 |
|
861 |
|
| 838 |
quit_pending = 1; |
862 |
if (c && c->ctl_fd != -1) { |
|
|
863 |
chan_read_failed(c); |
| 864 |
chan_write_failed(c); |
| 865 |
} else |
| 866 |
quit_pending = 1; |
| 839 |
return -1; |
867 |
return -1; |
| 840 |
|
868 |
|
| 841 |
case 'Z' - 64: |
869 |
case 'Z' - 64: |
|
|
870 |
/* XXX support this for mux clients */ |
| 871 |
if (c && c->ctl_fd != -1) { |
| 872 |
noescape: |
| 873 |
snprintf(string, sizeof string, |
| 874 |
"%c%c escape not available to " |
| 875 |
"multiplexed sessions\r\n", |
| 876 |
escape_char, ch); |
| 877 |
buffer_append(berr, string, |
| 878 |
strlen(string)); |
| 879 |
continue; |
| 880 |
} |
| 842 |
/* Suspend the program. */ |
881 |
/* Suspend the program. */ |
| 843 |
/* Print a message to that effect to the user. */ |
882 |
/* Print a message to that effect to the user. */ |
| 844 |
snprintf(string, sizeof string, "%c^Z [suspend ssh]\r\n", escape_char); |
883 |
snprintf(string, sizeof string, |
|
|
884 |
"%c^Z [suspend ssh]\r\n", escape_char); |
| 845 |
buffer_append(berr, string, strlen(string)); |
885 |
buffer_append(berr, string, strlen(string)); |
| 846 |
|
886 |
|
| 847 |
/* Restore terminal modes and suspend. */ |
887 |
/* Restore terminal modes and suspend. */ |
|
Lines 873-878
process_escapes(Buffer *bin, Buffer *bou
Link Here
|
| 873 |
continue; |
913 |
continue; |
| 874 |
|
914 |
|
| 875 |
case '&': |
915 |
case '&': |
|
|
916 |
if (c && c->ctl_fd != -1) |
| 917 |
goto noescape; |
| 876 |
/* |
918 |
/* |
| 877 |
* Detach the program (continue to serve connections, |
919 |
* Detach the program (continue to serve connections, |
| 878 |
* but put in background and no more new connections). |
920 |
* but put in background and no more new connections). |
|
Lines 921-947
process_escapes(Buffer *bin, Buffer *bou
Link Here
|
| 921 |
continue; |
963 |
continue; |
| 922 |
|
964 |
|
| 923 |
case '?': |
965 |
case '?': |
| 924 |
snprintf(string, sizeof string, |
966 |
if (c && c->ctl_fd != -1) { |
|
|
967 |
snprintf(string, sizeof string, |
| 968 |
"%c?\r\n\ |
| 969 |
Supported escape sequences:\r\n\ |
| 970 |
%c. - terminate session\r\n\ |
| 971 |
%cB - send a BREAK to the remote system\r\n\ |
| 972 |
%cC - open a command line\r\n\ |
| 973 |
%cR - Request rekey (SSH protocol 2 only)\r\n\ |
| 974 |
%c# - list forwarded connections\r\n\ |
| 975 |
%c? - this message\r\n\ |
| 976 |
%c%c - send the escape character by typing it twice\r\n\ |
| 977 |
(Note that escapes are only recognized immediately after newline.)\r\n", |
| 978 |
escape_char, escape_char, |
| 979 |
escape_char, escape_char, |
| 980 |
escape_char, escape_char, |
| 981 |
escape_char, escape_char, |
| 982 |
escape_char); |
| 983 |
} else { |
| 984 |
snprintf(string, sizeof string, |
| 925 |
"%c?\r\n\ |
985 |
"%c?\r\n\ |
| 926 |
Supported escape sequences:\r\n\ |
986 |
Supported escape sequences:\r\n\ |
| 927 |
%c. - terminate connection\r\n\ |
987 |
%c. - terminate connection (and any multiplexed sessions)\r\n\ |
| 928 |
%cB - send a BREAK to the remote system\r\n\ |
988 |
%cB - send a BREAK to the remote system\r\n\ |
| 929 |
%cC - open a command line\r\n\ |
989 |
%cC - open a command line\r\n\ |
| 930 |
%cR - Request rekey (SSH protocol 2 only)\r\n\ |
990 |
%cR - Request rekey (SSH protocol 2 only)\r\n\ |
| 931 |
%c^Z - suspend ssh\r\n\ |
991 |
%c^Z - suspend ssh\r\n\ |
| 932 |
%c# - list forwarded connections\r\n\ |
992 |
%c# - list forwarded connections\r\n\ |
| 933 |
%c& - background ssh (when waiting for connections to terminate)\r\n\ |
993 |
%c& - background ssh (when waiting for connections to terminate)\r\n\ |
| 934 |
%c? - this message\r\n\ |
994 |
%c? - this message\r\n\ |
| 935 |
%c%c - send the escape character by typing it twice\r\n\ |
995 |
%c%c - send the escape character by typing it twice\r\n\ |
| 936 |
(Note that escapes are only recognized immediately after newline.)\r\n", |
996 |
(Note that escapes are only recognized immediately after newline.)\r\n", |
| 937 |
escape_char, escape_char, escape_char, escape_char, |
997 |
escape_char, escape_char, |
| 938 |
escape_char, escape_char, escape_char, escape_char, |
998 |
escape_char, escape_char, |
| 939 |
escape_char, escape_char, escape_char); |
999 |
escape_char, escape_char, |
|
|
1000 |
escape_char, escape_char, |
| 1001 |
escape_char, escape_char, |
| 1002 |
escape_char); |
| 1003 |
} |
| 940 |
buffer_append(berr, string, strlen(string)); |
1004 |
buffer_append(berr, string, strlen(string)); |
| 941 |
continue; |
1005 |
continue; |
| 942 |
|
1006 |
|
| 943 |
case '#': |
1007 |
case '#': |
| 944 |
snprintf(string, sizeof string, "%c#\r\n", escape_char); |
1008 |
snprintf(string, sizeof string, "%c#\r\n", |
|
|
1009 |
escape_char); |
| 945 |
buffer_append(berr, string, strlen(string)); |
1010 |
buffer_append(berr, string, strlen(string)); |
| 946 |
s = channel_open_message(); |
1011 |
s = channel_open_message(); |
| 947 |
buffer_append(berr, s, strlen(s)); |
1012 |
buffer_append(berr, s, strlen(s)); |
|
Lines 967-973
Supported escape sequences:\r\n\
Link Here
|
| 967 |
*/ |
1032 |
*/ |
| 968 |
if (last_was_cr && ch == escape_char) { |
1033 |
if (last_was_cr && ch == escape_char) { |
| 969 |
/* It is. Set the flag and continue to next character. */ |
1034 |
/* It is. Set the flag and continue to next character. */ |
| 970 |
escape_pending = 1; |
1035 |
*escape_pendingp = 1; |
| 971 |
continue; |
1036 |
continue; |
| 972 |
} |
1037 |
} |
| 973 |
} |
1038 |
} |
|
Lines 1018-1024
client_process_input(fd_set *readset)
Link Here
|
| 1018 |
packet_start(SSH_CMSG_EOF); |
1083 |
packet_start(SSH_CMSG_EOF); |
| 1019 |
packet_send(); |
1084 |
packet_send(); |
| 1020 |
} |
1085 |
} |
| 1021 |
} else if (escape_char == SSH_ESCAPECHAR_NONE) { |
1086 |
} else if (escape_char1 == SSH_ESCAPECHAR_NONE) { |
| 1022 |
/* |
1087 |
/* |
| 1023 |
* Normal successful read, and no escape character. |
1088 |
* Normal successful read, and no escape character. |
| 1024 |
* Just append the data to buffer. |
1089 |
* Just append the data to buffer. |
|
Lines 1029-1036
client_process_input(fd_set *readset)
Link Here
|
| 1029 |
* Normal, successful read. But we have an escape character |
1094 |
* Normal, successful read. But we have an escape character |
| 1030 |
* and have to process the characters one by one. |
1095 |
* and have to process the characters one by one. |
| 1031 |
*/ |
1096 |
*/ |
| 1032 |
if (process_escapes(&stdin_buffer, &stdout_buffer, |
1097 |
if (process_escapes(NULL, &stdin_buffer, |
| 1033 |
&stderr_buffer, buf, len) == -1) |
1098 |
&stdout_buffer, &stderr_buffer, buf, len) == -1) |
| 1034 |
return; |
1099 |
return; |
| 1035 |
} |
1100 |
} |
| 1036 |
} |
1101 |
} |
|
Lines 1105-1117
client_process_buffered_input_packets(vo
Link Here
|
| 1105 |
|
1170 |
|
| 1106 |
/* scan buf[] for '~' before sending data to the peer */ |
1171 |
/* scan buf[] for '~' before sending data to the peer */ |
| 1107 |
|
1172 |
|
| 1108 |
static int |
1173 |
/* Helper: allocate a new escape_filter_ctx and fill in its escape char */ |
| 1109 |
simple_escape_filter(Channel *c, char *buf, int len) |
1174 |
void * |
|
|
1175 |
client_new_escape_filter_ctx(int escape_char) |
| 1176 |
{ |
| 1177 |
struct escape_filter_ctx *ret; |
| 1178 |
|
| 1179 |
ret = xmalloc(sizeof(*ret)); |
| 1180 |
ret->escape_pending = 0; |
| 1181 |
ret->escape_char = escape_char; |
| 1182 |
return (void *)ret; |
| 1183 |
} |
| 1184 |
|
| 1185 |
int |
| 1186 |
client_simple_escape_filter(Channel *c, char *buf, int len) |
| 1110 |
{ |
1187 |
{ |
| 1111 |
if (c->extended_usage != CHAN_EXTENDED_WRITE) |
1188 |
if (c->extended_usage != CHAN_EXTENDED_WRITE) |
| 1112 |
return 0; |
1189 |
return 0; |
| 1113 |
|
1190 |
|
| 1114 |
return process_escapes(&c->input, &c->output, &c->extended, buf, len); |
1191 |
return process_escapes(c, &c->input, &c->output, &c->extended, |
|
|
1192 |
buf, len); |
| 1115 |
} |
1193 |
} |
| 1116 |
|
1194 |
|
| 1117 |
static void |
1195 |
static void |
|
Lines 1143-1149
client_loop(int have_pty, int escape_cha
Link Here
|
| 1143 |
start_time = get_current_time(); |
1221 |
start_time = get_current_time(); |
| 1144 |
|
1222 |
|
| 1145 |
/* Initialize variables. */ |
1223 |
/* Initialize variables. */ |
| 1146 |
escape_pending = 0; |
1224 |
escape_pending1 = 0; |
| 1147 |
last_was_cr = 1; |
1225 |
last_was_cr = 1; |
| 1148 |
exit_status = -1; |
1226 |
exit_status = -1; |
| 1149 |
stdin_eof = 0; |
1227 |
stdin_eof = 0; |
|
Lines 1170-1176
client_loop(int have_pty, int escape_cha
Link Here
|
| 1170 |
stdout_bytes = 0; |
1248 |
stdout_bytes = 0; |
| 1171 |
stderr_bytes = 0; |
1249 |
stderr_bytes = 0; |
| 1172 |
quit_pending = 0; |
1250 |
quit_pending = 0; |
| 1173 |
escape_char = escape_char_arg; |
1251 |
escape_char1 = escape_char_arg; |
| 1174 |
|
1252 |
|
| 1175 |
/* Initialize buffers. */ |
1253 |
/* Initialize buffers. */ |
| 1176 |
buffer_init(&stdin_buffer); |
1254 |
buffer_init(&stdin_buffer); |
|
Lines 1198-1206
client_loop(int have_pty, int escape_cha
Link Here
|
| 1198 |
|
1276 |
|
| 1199 |
if (compat20) { |
1277 |
if (compat20) { |
| 1200 |
session_ident = ssh2_chan_id; |
1278 |
session_ident = ssh2_chan_id; |
| 1201 |
if (escape_char != SSH_ESCAPECHAR_NONE) |
1279 |
if (escape_char_arg != SSH_ESCAPECHAR_NONE) |
| 1202 |
channel_register_filter(session_ident, |
1280 |
channel_register_filter(session_ident, |
| 1203 |
simple_escape_filter, NULL); |
1281 |
client_simple_escape_filter, NULL, |
|
|
1282 |
client_new_escape_filter_ctx(escape_char_arg)); |
| 1204 |
if (session_ident != -1) |
1283 |
if (session_ident != -1) |
| 1205 |
channel_register_cleanup(session_ident, |
1284 |
channel_register_cleanup(session_ident, |
| 1206 |
client_channel_closed, 0); |
1285 |
client_channel_closed, 0); |