summaryrefslogtreecommitdiff
path: root/clientloop.c
diff options
context:
space:
mode:
Diffstat (limited to 'clientloop.c')
-rw-r--r--clientloop.c156
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"
62RCSID("$OpenBSD: clientloop.c,v 1.112 2003/06/28 16:23:06 deraadt Exp $"); 62RCSID("$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. */
90extern int stdin_null_flag; 90extern int stdin_null_flag;
91 91
92/* Flag indicating that no shell has been requested */
93extern 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). */
124static int connection_out; /* Connection to server (output). */ 127static int connection_out; /* Connection to server (output). */
125static int need_rekeying; /* Set to non-zero if rekeying is requested. */ 128static int need_rekeying; /* Set to non-zero if rekeying is requested. */
126static int session_closed = 0; /* In SSH2: login session closed. */ 129static int session_closed = 0; /* In SSH2: login session closed. */
130static int server_alive_timeouts = 0;
127 131
128static void client_init_dispatch(void); 132static void client_init_dispatch(void);
129int session_ident = -1; 133int 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
317static void
318client_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
324static void
325server_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
320static int 340static void
321client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, 341client_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
410static void 420static 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}
1169static void
1170client_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
1170static Channel * 1210static Channel *
1171client_request_forwarded_tcpip(const char *request_type, int rchan) 1211client_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 */
1468void
1469cleanup_exit(int i)
1470{
1471 leave_raw_mode();
1472 leave_non_blocking();
1473 _exit(i);
1474}