diff options
author | Colin Watson <cjwatson@debian.org> | 2004-03-01 02:25:32 +0000 |
---|---|---|
committer | Colin Watson <cjwatson@debian.org> | 2004-03-01 02:25:32 +0000 |
commit | ea8116a11e3de70036dbc665ccb0d486cf89cac9 (patch) | |
tree | d73ccdff78d8608e156465af42e6a1b3527fb2d6 /clientloop.c | |
parent | e39b311381a5609cc05acf298c42fba196dc524b (diff) | |
parent | f5bda272678ec6dccaa5f29379cf60cb855018e8 (diff) |
Merge 3.8p1 to the trunk. This builds and runs, but I haven't tested it
extensively yet.
ProtocolKeepAlives is now just a compatibility alias for
ServerAliveInterval.
Diffstat (limited to 'clientloop.c')
-rw-r--r-- | clientloop.c | 156 |
1 files changed, 103 insertions, 53 deletions
diff --git a/clientloop.c b/clientloop.c index d445230e5..626b29a5a 100644 --- a/clientloop.c +++ b/clientloop.c | |||
@@ -59,7 +59,7 @@ | |||
59 | */ | 59 | */ |
60 | 60 | ||
61 | #include "includes.h" | 61 | #include "includes.h" |
62 | RCSID("$OpenBSD: clientloop.c,v 1.112 2003/06/28 16:23:06 deraadt Exp $"); | 62 | RCSID("$OpenBSD: clientloop.c,v 1.117 2003/12/16 15:49:51 markus Exp $"); |
63 | 63 | ||
64 | #include "ssh.h" | 64 | #include "ssh.h" |
65 | #include "ssh1.h" | 65 | #include "ssh1.h" |
@@ -89,6 +89,9 @@ extern Options options; | |||
89 | /* Flag indicating that stdin should be redirected from /dev/null. */ | 89 | /* Flag indicating that stdin should be redirected from /dev/null. */ |
90 | extern int stdin_null_flag; | 90 | extern int stdin_null_flag; |
91 | 91 | ||
92 | /* Flag indicating that no shell has been requested */ | ||
93 | extern int no_shell_flag; | ||
94 | |||
92 | /* | 95 | /* |
93 | * Name of the host we are connecting to. This is the name given on the | 96 | * Name of the host we are connecting to. This is the name given on the |
94 | * command line, or the HostName specified for the user-supplied name in a | 97 | * command line, or the HostName specified for the user-supplied name in a |
@@ -124,6 +127,7 @@ static int connection_in; /* Connection to server (input). */ | |||
124 | static int connection_out; /* Connection to server (output). */ | 127 | static int connection_out; /* Connection to server (output). */ |
125 | static int need_rekeying; /* Set to non-zero if rekeying is requested. */ | 128 | static int need_rekeying; /* Set to non-zero if rekeying is requested. */ |
126 | static int session_closed = 0; /* In SSH2: login session closed. */ | 129 | static int session_closed = 0; /* In SSH2: login session closed. */ |
130 | static int server_alive_timeouts = 0; | ||
127 | 131 | ||
128 | static void client_init_dispatch(void); | 132 | static void client_init_dispatch(void); |
129 | int session_ident = -1; | 133 | int session_ident = -1; |
@@ -139,7 +143,6 @@ leave_non_blocking(void) | |||
139 | if (in_non_blocking_mode) { | 143 | if (in_non_blocking_mode) { |
140 | (void) fcntl(fileno(stdin), F_SETFL, 0); | 144 | (void) fcntl(fileno(stdin), F_SETFL, 0); |
141 | in_non_blocking_mode = 0; | 145 | in_non_blocking_mode = 0; |
142 | fatal_remove_cleanup((void (*) (void *)) leave_non_blocking, NULL); | ||
143 | } | 146 | } |
144 | } | 147 | } |
145 | 148 | ||
@@ -150,7 +153,6 @@ enter_non_blocking(void) | |||
150 | { | 153 | { |
151 | in_non_blocking_mode = 1; | 154 | in_non_blocking_mode = 1; |
152 | (void) fcntl(fileno(stdin), F_SETFL, O_NONBLOCK); | 155 | (void) fcntl(fileno(stdin), F_SETFL, O_NONBLOCK); |
153 | fatal_add_cleanup((void (*) (void *)) leave_non_blocking, NULL); | ||
154 | } | 156 | } |
155 | 157 | ||
156 | /* | 158 | /* |
@@ -312,18 +314,35 @@ client_check_window_change(void) | |||
312 | } | 314 | } |
313 | } | 315 | } |
314 | 316 | ||
317 | static void | ||
318 | client_global_request_reply(int type, u_int32_t seq, void *ctxt) | ||
319 | { | ||
320 | server_alive_timeouts = 0; | ||
321 | client_global_request_reply_fwd(type, seq, ctxt); | ||
322 | } | ||
323 | |||
324 | static void | ||
325 | server_alive_check(void) | ||
326 | { | ||
327 | if (++server_alive_timeouts > options.server_alive_count_max) | ||
328 | packet_disconnect("Timeout, server not responding."); | ||
329 | packet_start(SSH2_MSG_GLOBAL_REQUEST); | ||
330 | packet_put_cstring("keepalive@openssh.com"); | ||
331 | packet_put_char(1); /* boolean: want reply */ | ||
332 | packet_send(); | ||
333 | } | ||
334 | |||
315 | /* | 335 | /* |
316 | * Waits until the client can do something (some data becomes available on | 336 | * Waits until the client can do something (some data becomes available on |
317 | * one of the file descriptors). | 337 | * one of the file descriptors). |
318 | */ | 338 | */ |
319 | 339 | ||
320 | static int | 340 | static void |
321 | client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, | 341 | client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, |
322 | int *maxfdp, int *nallocp, int rekeying) | 342 | int *maxfdp, int *nallocp, int rekeying) |
323 | { | 343 | { |
324 | struct timeval tv, *tvp; | 344 | struct timeval tv, *tvp; |
325 | int n; | 345 | int ret; |
326 | extern Options options; | ||
327 | 346 | ||
328 | /* Add any selections by the channel mechanism. */ | 347 | /* Add any selections by the channel mechanism. */ |
329 | channel_prepare_select(readsetp, writesetp, maxfdp, nallocp, rekeying); | 348 | channel_prepare_select(readsetp, writesetp, maxfdp, nallocp, rekeying); |
@@ -353,7 +372,7 @@ client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, | |||
353 | /* clear mask since we did not call select() */ | 372 | /* clear mask since we did not call select() */ |
354 | memset(*readsetp, 0, *nallocp); | 373 | memset(*readsetp, 0, *nallocp); |
355 | memset(*writesetp, 0, *nallocp); | 374 | memset(*writesetp, 0, *nallocp); |
356 | return 0; | 375 | return; |
357 | } else { | 376 | } else { |
358 | FD_SET(connection_in, *readsetp); | 377 | FD_SET(connection_in, *readsetp); |
359 | } | 378 | } |
@@ -366,27 +385,18 @@ client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, | |||
366 | /* | 385 | /* |
367 | * Wait for something to happen. This will suspend the process until | 386 | * Wait for something to happen. This will suspend the process until |
368 | * some selected descriptor can be read, written, or has some other | 387 | * some selected descriptor can be read, written, or has some other |
369 | * event pending. Note: if you want to implement SSH_MSG_IGNORE | 388 | * event pending. |
370 | * messages to fool traffic analysis, this might be the place to do | ||
371 | * it: just have a random timeout for the select, and send a random | ||
372 | * SSH_MSG_IGNORE packet when the timeout expires. | ||
373 | */ | 389 | */ |
374 | 390 | ||
375 | /* | 391 | if (options.server_alive_interval == 0 || !compat20) |
376 | * We don't do the 'random' bit, but we want periodic ignored | 392 | tvp = NULL; |
377 | * message anyway, so as to notice when the other ends TCP | 393 | else { |
378 | * has given up during an outage. | 394 | tv.tv_sec = options.server_alive_interval; |
379 | */ | ||
380 | |||
381 | if (options.protocolkeepalives > 0) { | ||
382 | tvp = &tv; | ||
383 | tv.tv_sec = options.protocolkeepalives; | ||
384 | tv.tv_usec = 0; | 395 | tv.tv_usec = 0; |
385 | } else | 396 | tvp = &tv; |
386 | tvp = 0; | 397 | } |
387 | 398 | ret = select((*maxfdp)+1, *readsetp, *writesetp, NULL, tvp); | |
388 | n = select((*maxfdp)+1, *readsetp, *writesetp, NULL, tvp); | 399 | if (ret < 0) { |
389 | if (n < 0) { | ||
390 | char buf[100]; | 400 | char buf[100]; |
391 | 401 | ||
392 | /* | 402 | /* |
@@ -398,13 +408,13 @@ client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, | |||
398 | memset(*writesetp, 0, *nallocp); | 408 | memset(*writesetp, 0, *nallocp); |
399 | 409 | ||
400 | if (errno == EINTR) | 410 | if (errno == EINTR) |
401 | return 0; | 411 | return; |
402 | /* Note: we might still have data in the buffers. */ | 412 | /* Note: we might still have data in the buffers. */ |
403 | snprintf(buf, sizeof buf, "select: %s\r\n", strerror(errno)); | 413 | snprintf(buf, sizeof buf, "select: %s\r\n", strerror(errno)); |
404 | buffer_append(&stderr_buffer, buf, strlen(buf)); | 414 | buffer_append(&stderr_buffer, buf, strlen(buf)); |
405 | quit_pending = 1; | 415 | quit_pending = 1; |
406 | } | 416 | } else if (ret == 0) |
407 | return n == 0; | 417 | server_alive_check(); |
408 | } | 418 | } |
409 | 419 | ||
410 | static void | 420 | static void |
@@ -863,8 +873,7 @@ client_channel_closed(int id, void *arg) | |||
863 | id, session_ident); | 873 | id, session_ident); |
864 | channel_cancel_cleanup(id); | 874 | channel_cancel_cleanup(id); |
865 | session_closed = 1; | 875 | session_closed = 1; |
866 | if (in_raw_mode()) | 876 | leave_raw_mode(); |
867 | leave_raw_mode(); | ||
868 | } | 877 | } |
869 | 878 | ||
870 | /* | 879 | /* |
@@ -879,7 +888,6 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
879 | { | 888 | { |
880 | fd_set *readset = NULL, *writeset = NULL; | 889 | fd_set *readset = NULL, *writeset = NULL; |
881 | double start_time, total_time; | 890 | double start_time, total_time; |
882 | int timed_out; | ||
883 | int max_fd = 0, max_fd2 = 0, len, rekeying = 0, nalloc = 0; | 891 | int max_fd = 0, max_fd2 = 0, len, rekeying = 0, nalloc = 0; |
884 | char buf[100]; | 892 | char buf[100]; |
885 | 893 | ||
@@ -993,7 +1001,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
993 | * available on one of the descriptors). | 1001 | * available on one of the descriptors). |
994 | */ | 1002 | */ |
995 | max_fd2 = max_fd; | 1003 | max_fd2 = max_fd; |
996 | timed_out = client_wait_until_can_do_something(&readset, &writeset, | 1004 | client_wait_until_can_do_something(&readset, &writeset, |
997 | &max_fd2, &nalloc, rekeying); | 1005 | &max_fd2, &nalloc, rekeying); |
998 | 1006 | ||
999 | if (quit_pending) | 1007 | if (quit_pending) |
@@ -1016,21 +1024,6 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1016 | if (quit_pending) | 1024 | if (quit_pending) |
1017 | break; | 1025 | break; |
1018 | 1026 | ||
1019 | if(timed_out) { | ||
1020 | /* | ||
1021 | * Nothing is happening, so synthesize some | ||
1022 | * bogus activity | ||
1023 | */ | ||
1024 | packet_start(compat20 | ||
1025 | ? SSH2_MSG_IGNORE | ||
1026 | : SSH_MSG_IGNORE); | ||
1027 | packet_put_cstring(""); | ||
1028 | packet_send(); | ||
1029 | if (FD_ISSET(connection_out, writeset)) | ||
1030 | packet_write_poll(); | ||
1031 | continue; | ||
1032 | } | ||
1033 | |||
1034 | if (!compat20) { | 1027 | if (!compat20) { |
1035 | /* Buffer data from stdin */ | 1028 | /* Buffer data from stdin */ |
1036 | client_process_input(readset); | 1029 | client_process_input(readset); |
@@ -1069,12 +1062,19 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1069 | if (!isatty(fileno(stderr))) | 1062 | if (!isatty(fileno(stderr))) |
1070 | unset_nonblock(fileno(stderr)); | 1063 | unset_nonblock(fileno(stderr)); |
1071 | 1064 | ||
1072 | if (received_signal) { | 1065 | /* |
1073 | if (in_non_blocking_mode) /* XXX */ | 1066 | * If there was no shell or command requested, there will be no remote |
1074 | leave_non_blocking(); | 1067 | * exit status to be returned. In that case, clear error code if the |
1075 | fatal("Killed by signal %d.", (int) received_signal); | 1068 | * connection was deliberately terminated at this end. |
1069 | */ | ||
1070 | if (no_shell_flag && received_signal == SIGTERM) { | ||
1071 | received_signal = 0; | ||
1072 | exit_status = 0; | ||
1076 | } | 1073 | } |
1077 | 1074 | ||
1075 | if (received_signal) | ||
1076 | fatal("Killed by signal %d.", (int) received_signal); | ||
1077 | |||
1078 | /* | 1078 | /* |
1079 | * In interactive mode (with pseudo tty) display a message indicating | 1079 | * In interactive mode (with pseudo tty) display a message indicating |
1080 | * that the connection has been closed. | 1080 | * that the connection has been closed. |
@@ -1166,6 +1166,46 @@ client_input_exit_status(int type, u_int32_t seq, void *ctxt) | |||
1166 | /* Flag that we want to exit. */ | 1166 | /* Flag that we want to exit. */ |
1167 | quit_pending = 1; | 1167 | quit_pending = 1; |
1168 | } | 1168 | } |
1169 | static void | ||
1170 | client_input_agent_open(int type, u_int32_t seq, void *ctxt) | ||
1171 | { | ||
1172 | Channel *c = NULL; | ||
1173 | int remote_id, sock; | ||
1174 | |||
1175 | /* Read the remote channel number from the message. */ | ||
1176 | remote_id = packet_get_int(); | ||
1177 | packet_check_eom(); | ||
1178 | |||
1179 | /* | ||
1180 | * Get a connection to the local authentication agent (this may again | ||
1181 | * get forwarded). | ||
1182 | */ | ||
1183 | sock = ssh_get_authentication_socket(); | ||
1184 | |||
1185 | /* | ||
1186 | * If we could not connect the agent, send an error message back to | ||
1187 | * the server. This should never happen unless the agent dies, | ||
1188 | * because authentication forwarding is only enabled if we have an | ||
1189 | * agent. | ||
1190 | */ | ||
1191 | if (sock >= 0) { | ||
1192 | c = channel_new("", SSH_CHANNEL_OPEN, sock, sock, | ||
1193 | -1, 0, 0, 0, "authentication agent connection", 1); | ||
1194 | c->remote_id = remote_id; | ||
1195 | c->force_drain = 1; | ||
1196 | } | ||
1197 | if (c == NULL) { | ||
1198 | packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); | ||
1199 | packet_put_int(remote_id); | ||
1200 | } else { | ||
1201 | /* Send a confirmation to the remote host. */ | ||
1202 | debug("Forwarding authentication connection."); | ||
1203 | packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION); | ||
1204 | packet_put_int(remote_id); | ||
1205 | packet_put_int(c->self); | ||
1206 | } | ||
1207 | packet_send(); | ||
1208 | } | ||
1169 | 1209 | ||
1170 | static Channel * | 1210 | static Channel * |
1171 | client_request_forwarded_tcpip(const char *request_type, int rchan) | 1211 | client_request_forwarded_tcpip(const char *request_type, int rchan) |
@@ -1353,7 +1393,8 @@ client_input_global_request(int type, u_int32_t seq, void *ctxt) | |||
1353 | 1393 | ||
1354 | rtype = packet_get_string(NULL); | 1394 | rtype = packet_get_string(NULL); |
1355 | want_reply = packet_get_char(); | 1395 | want_reply = packet_get_char(); |
1356 | debug("client_input_global_request: rtype %s want_reply %d", rtype, want_reply); | 1396 | debug("client_input_global_request: rtype %s want_reply %d", |
1397 | rtype, want_reply); | ||
1357 | if (want_reply) { | 1398 | if (want_reply) { |
1358 | packet_start(success ? | 1399 | packet_start(success ? |
1359 | SSH2_MSG_REQUEST_SUCCESS : SSH2_MSG_REQUEST_FAILURE); | 1400 | SSH2_MSG_REQUEST_SUCCESS : SSH2_MSG_REQUEST_FAILURE); |
@@ -1401,7 +1442,7 @@ client_init_dispatch_13(void) | |||
1401 | dispatch_set(SSH_SMSG_STDOUT_DATA, &client_input_stdout_data); | 1442 | dispatch_set(SSH_SMSG_STDOUT_DATA, &client_input_stdout_data); |
1402 | 1443 | ||
1403 | dispatch_set(SSH_SMSG_AGENT_OPEN, options.forward_agent ? | 1444 | dispatch_set(SSH_SMSG_AGENT_OPEN, options.forward_agent ? |
1404 | &auth_input_open_request : &deny_input_open); | 1445 | &client_input_agent_open : &deny_input_open); |
1405 | dispatch_set(SSH_SMSG_X11_OPEN, options.forward_x11 ? | 1446 | dispatch_set(SSH_SMSG_X11_OPEN, options.forward_x11 ? |
1406 | &x11_input_open : &deny_input_open); | 1447 | &x11_input_open : &deny_input_open); |
1407 | } | 1448 | } |
@@ -1422,3 +1463,12 @@ client_init_dispatch(void) | |||
1422 | else | 1463 | else |
1423 | client_init_dispatch_15(); | 1464 | client_init_dispatch_15(); |
1424 | } | 1465 | } |
1466 | |||
1467 | /* client specific fatal cleanup */ | ||
1468 | void | ||
1469 | cleanup_exit(int i) | ||
1470 | { | ||
1471 | leave_raw_mode(); | ||
1472 | leave_non_blocking(); | ||
1473 | _exit(i); | ||
1474 | } | ||