diff options
Diffstat (limited to 'clientloop.c')
-rw-r--r-- | clientloop.c | 210 |
1 files changed, 153 insertions, 57 deletions
diff --git a/clientloop.c b/clientloop.c index 1bc6d7e67..4f2e5037d 100644 --- a/clientloop.c +++ b/clientloop.c | |||
@@ -12,10 +12,11 @@ | |||
12 | * | 12 | * |
13 | * The main loop for the interactive session (client side). | 13 | * The main loop for the interactive session (client side). |
14 | * | 14 | * |
15 | * SSH2 support added by Markus Friedl. | ||
15 | */ | 16 | */ |
16 | 17 | ||
17 | #include "includes.h" | 18 | #include "includes.h" |
18 | RCSID("$Id: clientloop.c,v 1.8 2000/04/01 01:09:23 damien Exp $"); | 19 | RCSID("$Id: clientloop.c,v 1.9 2000/04/06 02:32:39 damien Exp $"); |
19 | 20 | ||
20 | #include "xmalloc.h" | 21 | #include "xmalloc.h" |
21 | #include "ssh.h" | 22 | #include "ssh.h" |
@@ -24,6 +25,7 @@ RCSID("$Id: clientloop.c,v 1.8 2000/04/01 01:09:23 damien Exp $"); | |||
24 | #include "authfd.h" | 25 | #include "authfd.h" |
25 | #include "readconf.h" | 26 | #include "readconf.h" |
26 | 27 | ||
28 | #include "ssh2.h" | ||
27 | #include "compat.h" | 29 | #include "compat.h" |
28 | #include "channels.h" | 30 | #include "channels.h" |
29 | #include "dispatch.h" | 31 | #include "dispatch.h" |
@@ -75,6 +77,10 @@ static unsigned long stdin_bytes, stdout_bytes, stderr_bytes; | |||
75 | static int quit_pending; /* Set to non-zero to quit the client loop. */ | 77 | static int quit_pending; /* Set to non-zero to quit the client loop. */ |
76 | static int escape_char; /* Escape character. */ | 78 | static int escape_char; /* Escape character. */ |
77 | 79 | ||
80 | |||
81 | void client_init_dispatch(void); | ||
82 | int session_ident = -1; | ||
83 | |||
78 | /* Returns the user\'s terminal to normal mode if it had been put in raw mode. */ | 84 | /* Returns the user\'s terminal to normal mode if it had been put in raw mode. */ |
79 | 85 | ||
80 | void | 86 | void |
@@ -273,23 +279,32 @@ client_make_packets_from_stdin_data() | |||
273 | void | 279 | void |
274 | client_check_window_change() | 280 | client_check_window_change() |
275 | { | 281 | { |
276 | /* Send possible window change message to the server. */ | 282 | struct winsize ws; |
277 | if (received_window_change_signal) { | 283 | |
278 | struct winsize ws; | 284 | if (! received_window_change_signal) |
279 | 285 | return; | |
280 | /* Clear the window change indicator. */ | 286 | /** XXX race */ |
281 | received_window_change_signal = 0; | 287 | received_window_change_signal = 0; |
282 | 288 | ||
283 | /* Read new window size. */ | 289 | if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0) |
284 | if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) >= 0) { | 290 | return; |
285 | /* Successful, send the packet now. */ | 291 | |
286 | packet_start(SSH_CMSG_WINDOW_SIZE); | 292 | debug("client_check_window_change: changed"); |
287 | packet_put_int(ws.ws_row); | 293 | |
288 | packet_put_int(ws.ws_col); | 294 | if (compat20) { |
289 | packet_put_int(ws.ws_xpixel); | 295 | channel_request_start(session_ident, "window-change", 0); |
290 | packet_put_int(ws.ws_ypixel); | 296 | packet_put_int(ws.ws_col); |
291 | packet_send(); | 297 | packet_put_int(ws.ws_row); |
292 | } | 298 | packet_put_int(ws.ws_xpixel); |
299 | packet_put_int(ws.ws_ypixel); | ||
300 | packet_send(); | ||
301 | } else { | ||
302 | packet_start(SSH_CMSG_WINDOW_SIZE); | ||
303 | packet_put_int(ws.ws_row); | ||
304 | packet_put_int(ws.ws_col); | ||
305 | packet_put_int(ws.ws_xpixel); | ||
306 | packet_put_int(ws.ws_ypixel); | ||
307 | packet_send(); | ||
293 | } | 308 | } |
294 | } | 309 | } |
295 | 310 | ||
@@ -301,23 +316,33 @@ client_check_window_change() | |||
301 | void | 316 | void |
302 | client_wait_until_can_do_something(fd_set * readset, fd_set * writeset) | 317 | client_wait_until_can_do_something(fd_set * readset, fd_set * writeset) |
303 | { | 318 | { |
319 | /*debug("client_wait_until_can_do_something"); */ | ||
320 | |||
304 | /* Initialize select masks. */ | 321 | /* Initialize select masks. */ |
305 | FD_ZERO(readset); | 322 | FD_ZERO(readset); |
323 | FD_ZERO(writeset); | ||
306 | 324 | ||
307 | /* Read from the connection, unless our buffers are full. */ | 325 | if (!compat20) { |
308 | if (buffer_len(&stdout_buffer) < buffer_high && | 326 | /* Read from the connection, unless our buffers are full. */ |
309 | buffer_len(&stderr_buffer) < buffer_high && | 327 | if (buffer_len(&stdout_buffer) < buffer_high && |
310 | channel_not_very_much_buffered_data()) | 328 | buffer_len(&stderr_buffer) < buffer_high && |
329 | channel_not_very_much_buffered_data()) | ||
330 | FD_SET(connection_in, readset); | ||
331 | /* | ||
332 | * Read from stdin, unless we have seen EOF or have very much | ||
333 | * buffered data to send to the server. | ||
334 | */ | ||
335 | if (!stdin_eof && packet_not_very_much_data_to_write()) | ||
336 | FD_SET(fileno(stdin), readset); | ||
337 | |||
338 | /* Select stdout/stderr if have data in buffer. */ | ||
339 | if (buffer_len(&stdout_buffer) > 0) | ||
340 | FD_SET(fileno(stdout), writeset); | ||
341 | if (buffer_len(&stderr_buffer) > 0) | ||
342 | FD_SET(fileno(stderr), writeset); | ||
343 | } else { | ||
311 | FD_SET(connection_in, readset); | 344 | FD_SET(connection_in, readset); |
312 | 345 | } | |
313 | /* | ||
314 | * Read from stdin, unless we have seen EOF or have very much | ||
315 | * buffered data to send to the server. | ||
316 | */ | ||
317 | if (!stdin_eof && packet_not_very_much_data_to_write()) | ||
318 | FD_SET(fileno(stdin), readset); | ||
319 | |||
320 | FD_ZERO(writeset); | ||
321 | 346 | ||
322 | /* Add any selections by the channel mechanism. */ | 347 | /* Add any selections by the channel mechanism. */ |
323 | channel_prepare_select(readset, writeset); | 348 | channel_prepare_select(readset, writeset); |
@@ -326,14 +351,7 @@ client_wait_until_can_do_something(fd_set * readset, fd_set * writeset) | |||
326 | if (packet_have_data_to_write()) | 351 | if (packet_have_data_to_write()) |
327 | FD_SET(connection_out, writeset); | 352 | FD_SET(connection_out, writeset); |
328 | 353 | ||
329 | /* Select stdout if have data in buffer. */ | 354 | /* move UP XXX */ |
330 | if (buffer_len(&stdout_buffer) > 0) | ||
331 | FD_SET(fileno(stdout), writeset); | ||
332 | |||
333 | /* Select stderr if have data in buffer. */ | ||
334 | if (buffer_len(&stderr_buffer) > 0) | ||
335 | FD_SET(fileno(stderr), writeset); | ||
336 | |||
337 | /* Update maximum file descriptor number, if appropriate. */ | 355 | /* Update maximum file descriptor number, if appropriate. */ |
338 | if (channel_max_fd() > max_fd) | 356 | if (channel_max_fd() > max_fd) |
339 | max_fd = channel_max_fd(); | 357 | max_fd = channel_max_fd(); |
@@ -408,10 +426,10 @@ client_suspend_self() | |||
408 | } | 426 | } |
409 | 427 | ||
410 | void | 428 | void |
411 | client_process_input(fd_set * readset) | 429 | client_process_net_input(fd_set * readset) |
412 | { | 430 | { |
413 | int len, pid; | 431 | int len; |
414 | char buf[8192], *s; | 432 | char buf[8192]; |
415 | 433 | ||
416 | /* | 434 | /* |
417 | * Read input from the server, and add any such data to the buffer of | 435 | * Read input from the server, and add any such data to the buffer of |
@@ -420,6 +438,7 @@ client_process_input(fd_set * readset) | |||
420 | if (FD_ISSET(connection_in, readset)) { | 438 | if (FD_ISSET(connection_in, readset)) { |
421 | /* Read as much as possible. */ | 439 | /* Read as much as possible. */ |
422 | len = read(connection_in, buf, sizeof(buf)); | 440 | len = read(connection_in, buf, sizeof(buf)); |
441 | /*debug("read connection_in len %d", len); XXX */ | ||
423 | if (len == 0) { | 442 | if (len == 0) { |
424 | /* Received EOF. The remote host has closed the connection. */ | 443 | /* Received EOF. The remote host has closed the connection. */ |
425 | snprintf(buf, sizeof buf, "Connection to %.300s closed by remote host.\r\n", | 444 | snprintf(buf, sizeof buf, "Connection to %.300s closed by remote host.\r\n", |
@@ -447,6 +466,14 @@ client_process_input(fd_set * readset) | |||
447 | } | 466 | } |
448 | packet_process_incoming(buf, len); | 467 | packet_process_incoming(buf, len); |
449 | } | 468 | } |
469 | } | ||
470 | |||
471 | void | ||
472 | client_process_input(fd_set * readset) | ||
473 | { | ||
474 | int len, pid; | ||
475 | char buf[8192], *s; | ||
476 | |||
450 | /* Read input from stdin. */ | 477 | /* Read input from stdin. */ |
451 | if (FD_ISSET(fileno(stdin), readset)) { | 478 | if (FD_ISSET(fileno(stdin), readset)) { |
452 | /* Read as much as possible. */ | 479 | /* Read as much as possible. */ |
@@ -703,8 +730,6 @@ client_process_buffered_input_packets() | |||
703 | * character for terminating or suspending the session. | 730 | * character for terminating or suspending the session. |
704 | */ | 731 | */ |
705 | 732 | ||
706 | void client_init_dispatch(void); | ||
707 | |||
708 | int | 733 | int |
709 | client_loop(int have_pty, int escape_char_arg) | 734 | client_loop(int have_pty, int escape_char_arg) |
710 | { | 735 | { |
@@ -753,7 +778,8 @@ client_loop(int have_pty, int escape_char_arg) | |||
753 | enter_raw_mode(); | 778 | enter_raw_mode(); |
754 | 779 | ||
755 | /* Check if we should immediately send of on stdin. */ | 780 | /* Check if we should immediately send of on stdin. */ |
756 | client_check_initial_eof_on_stdin(); | 781 | if (!compat20) |
782 | client_check_initial_eof_on_stdin(); | ||
757 | 783 | ||
758 | /* Main loop of the client for the interactive session mode. */ | 784 | /* Main loop of the client for the interactive session mode. */ |
759 | while (!quit_pending) { | 785 | while (!quit_pending) { |
@@ -762,11 +788,17 @@ client_loop(int have_pty, int escape_char_arg) | |||
762 | /* Process buffered packets sent by the server. */ | 788 | /* Process buffered packets sent by the server. */ |
763 | client_process_buffered_input_packets(); | 789 | client_process_buffered_input_packets(); |
764 | 790 | ||
791 | if (compat20 && !channel_still_open()) { | ||
792 | debug("!channel_still_open."); | ||
793 | break; | ||
794 | } | ||
795 | |||
765 | /* | 796 | /* |
766 | * Make packets of buffered stdin data, and buffer them for | 797 | * Make packets of buffered stdin data, and buffer them for |
767 | * sending to the server. | 798 | * sending to the server. |
768 | */ | 799 | */ |
769 | client_make_packets_from_stdin_data(); | 800 | if (!compat20) |
801 | client_make_packets_from_stdin_data(); | ||
770 | 802 | ||
771 | /* | 803 | /* |
772 | * Make packets from buffered channel data, and buffer them | 804 | * Make packets from buffered channel data, and buffer them |
@@ -796,17 +828,21 @@ client_loop(int have_pty, int escape_char_arg) | |||
796 | /* Do channel operations. */ | 828 | /* Do channel operations. */ |
797 | channel_after_select(&readset, &writeset); | 829 | channel_after_select(&readset, &writeset); |
798 | 830 | ||
799 | /* | 831 | /* Buffer input from the connection. */ |
800 | * Process input from the connection and from stdin. Buffer | 832 | client_process_net_input(&readset); |
801 | * any data that is available. | ||
802 | */ | ||
803 | client_process_input(&readset); | ||
804 | 833 | ||
805 | /* | 834 | if (quit_pending) |
806 | * Process output to stdout and stderr. Output to the | 835 | break; |
807 | * connection is processed elsewhere (above). | 836 | |
808 | */ | 837 | if (!compat20) { |
809 | client_process_output(&writeset); | 838 | /* Buffer data from stdin */ |
839 | client_process_input(&readset); | ||
840 | /* | ||
841 | * Process output to stdout and stderr. Output to | ||
842 | * the connection is processed elsewhere (above). | ||
843 | */ | ||
844 | client_process_output(&writeset); | ||
845 | } | ||
810 | 846 | ||
811 | /* Send as much buffered packet data as possible to the sender. */ | 847 | /* Send as much buffered packet data as possible to the sender. */ |
812 | if (FD_ISSET(connection_out, &writeset)) | 848 | if (FD_ISSET(connection_out, &writeset)) |
@@ -918,6 +954,19 @@ client_input_exit_status(int type, int plen) | |||
918 | } | 954 | } |
919 | 955 | ||
920 | void | 956 | void |
957 | client_init_dispatch_20() | ||
958 | { | ||
959 | dispatch_init(&dispatch_protocol_error); | ||
960 | dispatch_set(SSH2_MSG_CHANNEL_CLOSE, &channel_input_oclose); | ||
961 | dispatch_set(SSH2_MSG_CHANNEL_DATA, &channel_input_data); | ||
962 | dispatch_set(SSH2_MSG_CHANNEL_EOF, &channel_input_ieof); | ||
963 | dispatch_set(SSH2_MSG_CHANNEL_EXTENDED_DATA, &channel_input_extended_data); | ||
964 | dispatch_set(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation); | ||
965 | dispatch_set(SSH2_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure); | ||
966 | dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &channel_input_channel_request); | ||
967 | dispatch_set(SSH2_MSG_CHANNEL_WINDOW_ADJUST, &channel_input_window_adjust); | ||
968 | } | ||
969 | void | ||
921 | client_init_dispatch_13() | 970 | client_init_dispatch_13() |
922 | { | 971 | { |
923 | dispatch_init(NULL); | 972 | dispatch_init(NULL); |
@@ -944,8 +993,55 @@ client_init_dispatch_15() | |||
944 | void | 993 | void |
945 | client_init_dispatch() | 994 | client_init_dispatch() |
946 | { | 995 | { |
947 | if (compat13) | 996 | if (compat20) |
997 | client_init_dispatch_20(); | ||
998 | else if (compat13) | ||
948 | client_init_dispatch_13(); | 999 | client_init_dispatch_13(); |
949 | else | 1000 | else |
950 | client_init_dispatch_15(); | 1001 | client_init_dispatch_15(); |
951 | } | 1002 | } |
1003 | |||
1004 | void | ||
1005 | client_input_channel_req(int id, void *arg) | ||
1006 | { | ||
1007 | Channel *c = NULL; | ||
1008 | unsigned int len; | ||
1009 | int success = 0; | ||
1010 | int reply; | ||
1011 | char *rtype; | ||
1012 | |||
1013 | rtype = packet_get_string(&len); | ||
1014 | reply = packet_get_char(); | ||
1015 | |||
1016 | log("session_input_channel_req: rtype %s reply %d", rtype, reply); | ||
1017 | |||
1018 | c = channel_lookup(id); | ||
1019 | if (c == NULL) | ||
1020 | fatal("session_input_channel_req: channel %d: bad channel", id); | ||
1021 | |||
1022 | if (session_ident == -1) { | ||
1023 | error("client_input_channel_req: no channel %d", id); | ||
1024 | } else if (id != session_ident) { | ||
1025 | error("client_input_channel_req: bad channel %d != %d", | ||
1026 | id, session_ident); | ||
1027 | } else if (strcmp(rtype, "exit-status") == 0) { | ||
1028 | success = 1; | ||
1029 | exit_status = packet_get_int(); | ||
1030 | } | ||
1031 | if (reply) { | ||
1032 | packet_start(success ? | ||
1033 | SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE); | ||
1034 | packet_put_int(c->remote_id); | ||
1035 | packet_send(); | ||
1036 | } | ||
1037 | xfree(rtype); | ||
1038 | } | ||
1039 | |||
1040 | void | ||
1041 | client_set_session_ident(int id) | ||
1042 | { | ||
1043 | debug("client_set_session_ident: id %d", id); | ||
1044 | session_ident = id; | ||
1045 | channel_register_callback(id, SSH2_MSG_CHANNEL_REQUEST, | ||
1046 | client_input_channel_req, (void *)0); | ||
1047 | } | ||