diff options
author | Colin Watson <cjwatson@debian.org> | 2017-10-04 11:23:58 +0100 |
---|---|---|
committer | Colin Watson <cjwatson@debian.org> | 2017-10-05 23:58:12 +0100 |
commit | 0556ea972b15607b7e13ff31bc05840881c91dd3 (patch) | |
tree | d6b8d48062d0278b5ae0eeff42d0e9afa9f26860 /clientloop.c | |
parent | db2122d97eb1ecdd8d99b7bf79b0dd2b5addfd92 (diff) | |
parent | 801a62eedaaf47b20dbf4b426dc3e084bf0c8d49 (diff) |
New upstream release (7.6p1)
Diffstat (limited to 'clientloop.c')
-rw-r--r-- | clientloop.c | 853 |
1 files changed, 194 insertions, 659 deletions
diff --git a/clientloop.c b/clientloop.c index 06845280e..0010b8337 100644 --- a/clientloop.c +++ b/clientloop.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: clientloop.c,v 1.291 2017/03/10 05:01:13 djm Exp $ */ | 1 | /* $OpenBSD: clientloop.c,v 1.305 2017/09/19 04:24:22 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 |
@@ -89,7 +89,6 @@ | |||
89 | #include "openbsd-compat/sys-queue.h" | 89 | #include "openbsd-compat/sys-queue.h" |
90 | #include "xmalloc.h" | 90 | #include "xmalloc.h" |
91 | #include "ssh.h" | 91 | #include "ssh.h" |
92 | #include "ssh1.h" | ||
93 | #include "ssh2.h" | 92 | #include "ssh2.h" |
94 | #include "packet.h" | 93 | #include "packet.h" |
95 | #include "buffer.h" | 94 | #include "buffer.h" |
@@ -156,15 +155,9 @@ static time_t control_persist_exit_time = 0; | |||
156 | 155 | ||
157 | /* Common data for the client loop code. */ | 156 | /* Common data for the client loop code. */ |
158 | volatile sig_atomic_t quit_pending; /* Set non-zero to quit the loop. */ | 157 | volatile sig_atomic_t quit_pending; /* Set non-zero to quit the loop. */ |
159 | static int escape_char1; /* Escape character. (proto1 only) */ | ||
160 | static int escape_pending1; /* Last character was an escape (proto1 only) */ | ||
161 | static int last_was_cr; /* Last character was a newline. */ | 158 | static int last_was_cr; /* Last character was a newline. */ |
162 | static int exit_status; /* Used to store the command exit status. */ | 159 | static int exit_status; /* Used to store the command exit status. */ |
163 | static int stdin_eof; /* EOF has been encountered on stderr. */ | 160 | static Buffer stderr_buffer; /* Used for final exit message. */ |
164 | static Buffer stdin_buffer; /* Buffer for stdin data. */ | ||
165 | static Buffer stdout_buffer; /* Buffer for stdout data. */ | ||
166 | static Buffer stderr_buffer; /* Buffer for stderr data. */ | ||
167 | static u_int buffer_high; /* Soft max buffer size. */ | ||
168 | static int connection_in; /* Connection to server (input). */ | 161 | static int connection_in; /* Connection to server (input). */ |
169 | static int connection_out; /* Connection to server (output). */ | 162 | static int connection_out; /* Connection to server (output). */ |
170 | static int need_rekeying; /* Set to non-zero if rekeying is requested. */ | 163 | static int need_rekeying; /* Set to non-zero if rekeying is requested. */ |
@@ -188,6 +181,7 @@ struct channel_reply_ctx { | |||
188 | }; | 181 | }; |
189 | 182 | ||
190 | /* Global request success/failure callbacks */ | 183 | /* Global request success/failure callbacks */ |
184 | /* XXX move to struct ssh? */ | ||
191 | struct global_confirm { | 185 | struct global_confirm { |
192 | TAILQ_ENTRY(global_confirm) entry; | 186 | TAILQ_ENTRY(global_confirm) entry; |
193 | global_confirm_cb *cb; | 187 | global_confirm_cb *cb; |
@@ -211,15 +205,6 @@ leave_non_blocking(void) | |||
211 | } | 205 | } |
212 | } | 206 | } |
213 | 207 | ||
214 | /* Puts stdin terminal in non-blocking mode. */ | ||
215 | |||
216 | static void | ||
217 | enter_non_blocking(void) | ||
218 | { | ||
219 | in_non_blocking_mode = 1; | ||
220 | set_nonblock(fileno(stdin)); | ||
221 | } | ||
222 | |||
223 | /* | 208 | /* |
224 | * Signal handler for the window change signal (SIGWINCH). This just sets a | 209 | * Signal handler for the window change signal (SIGWINCH). This just sets a |
225 | * flag indicating that the window has changed. | 210 | * flag indicating that the window has changed. |
@@ -264,13 +249,13 @@ get_current_time(void) | |||
264 | * control master process, or if there is no ControlPersist timeout. | 249 | * control master process, or if there is no ControlPersist timeout. |
265 | */ | 250 | */ |
266 | static void | 251 | static void |
267 | set_control_persist_exit_time(void) | 252 | set_control_persist_exit_time(struct ssh *ssh) |
268 | { | 253 | { |
269 | if (muxserver_sock == -1 || !options.control_persist | 254 | if (muxserver_sock == -1 || !options.control_persist |
270 | || options.control_persist_timeout == 0) { | 255 | || options.control_persist_timeout == 0) { |
271 | /* not using a ControlPersist timeout */ | 256 | /* not using a ControlPersist timeout */ |
272 | control_persist_exit_time = 0; | 257 | control_persist_exit_time = 0; |
273 | } else if (channel_still_open()) { | 258 | } else if (channel_still_open(ssh)) { |
274 | /* some client connections are still open */ | 259 | /* some client connections are still open */ |
275 | if (control_persist_exit_time > 0) | 260 | if (control_persist_exit_time > 0) |
276 | debug2("%s: cancel scheduled exit", __func__); | 261 | debug2("%s: cancel scheduled exit", __func__); |
@@ -308,8 +293,9 @@ client_x11_display_valid(const char *display) | |||
308 | #define SSH_X11_PROTO "MIT-MAGIC-COOKIE-1" | 293 | #define SSH_X11_PROTO "MIT-MAGIC-COOKIE-1" |
309 | #define X11_TIMEOUT_SLACK 60 | 294 | #define X11_TIMEOUT_SLACK 60 |
310 | int | 295 | int |
311 | client_x11_get_proto(const char *display, const char *xauth_path, | 296 | client_x11_get_proto(struct ssh *ssh, const char *display, |
312 | u_int trusted, u_int timeout, char **_proto, char **_data) | 297 | const char *xauth_path, u_int trusted, u_int timeout, |
298 | char **_proto, char **_data) | ||
313 | { | 299 | { |
314 | char cmd[1024], line[512], xdisplay[512]; | 300 | char cmd[1024], line[512], xdisplay[512]; |
315 | char xauthfile[PATH_MAX], xauthdir[PATH_MAX]; | 301 | char xauthfile[PATH_MAX], xauthdir[PATH_MAX]; |
@@ -393,7 +379,8 @@ client_x11_get_proto(const char *display, const char *xauth_path, | |||
393 | x11_refuse_time = UINT_MAX; | 379 | x11_refuse_time = UINT_MAX; |
394 | else | 380 | else |
395 | x11_refuse_time = now + timeout; | 381 | x11_refuse_time = now + timeout; |
396 | channel_set_x11_refuse_time(x11_refuse_time); | 382 | channel_set_x11_refuse_time(ssh, |
383 | x11_refuse_time); | ||
397 | } | 384 | } |
398 | if (system(cmd) == 0) | 385 | if (system(cmd) == 0) |
399 | generated = 1; | 386 | generated = 1; |
@@ -459,91 +446,6 @@ client_x11_get_proto(const char *display, const char *xauth_path, | |||
459 | } | 446 | } |
460 | 447 | ||
461 | /* | 448 | /* |
462 | * This is called when the interactive is entered. This checks if there is | ||
463 | * an EOF coming on stdin. We must check this explicitly, as select() does | ||
464 | * not appear to wake up when redirecting from /dev/null. | ||
465 | */ | ||
466 | |||
467 | static void | ||
468 | client_check_initial_eof_on_stdin(void) | ||
469 | { | ||
470 | int len; | ||
471 | char buf[1]; | ||
472 | |||
473 | /* | ||
474 | * If standard input is to be "redirected from /dev/null", we simply | ||
475 | * mark that we have seen an EOF and send an EOF message to the | ||
476 | * server. Otherwise, we try to read a single character; it appears | ||
477 | * that for some files, such /dev/null, select() never wakes up for | ||
478 | * read for this descriptor, which means that we never get EOF. This | ||
479 | * way we will get the EOF if stdin comes from /dev/null or similar. | ||
480 | */ | ||
481 | if (stdin_null_flag) { | ||
482 | /* Fake EOF on stdin. */ | ||
483 | debug("Sending eof."); | ||
484 | stdin_eof = 1; | ||
485 | packet_start(SSH_CMSG_EOF); | ||
486 | packet_send(); | ||
487 | } else { | ||
488 | enter_non_blocking(); | ||
489 | |||
490 | /* Check for immediate EOF on stdin. */ | ||
491 | len = read(fileno(stdin), buf, 1); | ||
492 | if (len == 0) { | ||
493 | /* | ||
494 | * EOF. Record that we have seen it and send | ||
495 | * EOF to server. | ||
496 | */ | ||
497 | debug("Sending eof."); | ||
498 | stdin_eof = 1; | ||
499 | packet_start(SSH_CMSG_EOF); | ||
500 | packet_send(); | ||
501 | } else if (len > 0) { | ||
502 | /* | ||
503 | * Got data. We must store the data in the buffer, | ||
504 | * and also process it as an escape character if | ||
505 | * appropriate. | ||
506 | */ | ||
507 | if ((u_char) buf[0] == escape_char1) | ||
508 | escape_pending1 = 1; | ||
509 | else | ||
510 | buffer_append(&stdin_buffer, buf, 1); | ||
511 | } | ||
512 | leave_non_blocking(); | ||
513 | } | ||
514 | } | ||
515 | |||
516 | |||
517 | /* | ||
518 | * Make packets from buffered stdin data, and buffer them for sending to the | ||
519 | * connection. | ||
520 | */ | ||
521 | |||
522 | static void | ||
523 | client_make_packets_from_stdin_data(void) | ||
524 | { | ||
525 | u_int len; | ||
526 | |||
527 | /* Send buffered stdin data to the server. */ | ||
528 | while (buffer_len(&stdin_buffer) > 0 && | ||
529 | packet_not_very_much_data_to_write()) { | ||
530 | len = buffer_len(&stdin_buffer); | ||
531 | /* Keep the packets at reasonable size. */ | ||
532 | if (len > packet_get_maxsize()) | ||
533 | len = packet_get_maxsize(); | ||
534 | packet_start(SSH_CMSG_STDIN_DATA); | ||
535 | packet_put_string(buffer_ptr(&stdin_buffer), len); | ||
536 | packet_send(); | ||
537 | buffer_consume(&stdin_buffer, len); | ||
538 | /* If we have a pending EOF, send it now. */ | ||
539 | if (stdin_eof && buffer_len(&stdin_buffer) == 0) { | ||
540 | packet_start(SSH_CMSG_EOF); | ||
541 | packet_send(); | ||
542 | } | ||
543 | } | ||
544 | } | ||
545 | |||
546 | /* | ||
547 | * Checks if the client window has changed, and sends a packet about it to | 449 | * Checks if the client window has changed, and sends a packet about it to |
548 | * the server if so. The actual change is detected elsewhere (by a software | 450 | * the server if so. The actual change is detected elsewhere (by a software |
549 | * interrupt on Unix); this just checks the flag and sends a message if | 451 | * interrupt on Unix); this just checks the flag and sends a message if |
@@ -551,40 +453,27 @@ client_make_packets_from_stdin_data(void) | |||
551 | */ | 453 | */ |
552 | 454 | ||
553 | static void | 455 | static void |
554 | client_check_window_change(void) | 456 | client_check_window_change(struct ssh *ssh) |
555 | { | 457 | { |
556 | struct winsize ws; | 458 | if (!received_window_change_signal) |
557 | |||
558 | if (! received_window_change_signal) | ||
559 | return; | 459 | return; |
560 | /** XXX race */ | 460 | /** XXX race */ |
561 | received_window_change_signal = 0; | 461 | received_window_change_signal = 0; |
562 | 462 | ||
563 | debug2("client_check_window_change: changed"); | 463 | debug2("%s: changed", __func__); |
564 | 464 | ||
565 | if (compat20) { | 465 | channel_send_window_changes(ssh); |
566 | channel_send_window_changes(); | ||
567 | } else { | ||
568 | if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0) | ||
569 | return; | ||
570 | packet_start(SSH_CMSG_WINDOW_SIZE); | ||
571 | packet_put_int((u_int)ws.ws_row); | ||
572 | packet_put_int((u_int)ws.ws_col); | ||
573 | packet_put_int((u_int)ws.ws_xpixel); | ||
574 | packet_put_int((u_int)ws.ws_ypixel); | ||
575 | packet_send(); | ||
576 | } | ||
577 | } | 466 | } |
578 | 467 | ||
579 | static int | 468 | static int |
580 | client_global_request_reply(int type, u_int32_t seq, void *ctxt) | 469 | client_global_request_reply(int type, u_int32_t seq, struct ssh *ssh) |
581 | { | 470 | { |
582 | struct global_confirm *gc; | 471 | struct global_confirm *gc; |
583 | 472 | ||
584 | if ((gc = TAILQ_FIRST(&global_confirms)) == NULL) | 473 | if ((gc = TAILQ_FIRST(&global_confirms)) == NULL) |
585 | return 0; | 474 | return 0; |
586 | if (gc->cb != NULL) | 475 | if (gc->cb != NULL) |
587 | gc->cb(type, seq, gc->ctx); | 476 | gc->cb(ssh, type, seq, gc->ctx); |
588 | if (--gc->ref_count <= 0) { | 477 | if (--gc->ref_count <= 0) { |
589 | TAILQ_REMOVE(&global_confirms, gc, entry); | 478 | TAILQ_REMOVE(&global_confirms, gc, entry); |
590 | explicit_bzero(gc, sizeof(*gc)); | 479 | explicit_bzero(gc, sizeof(*gc)); |
@@ -615,7 +504,8 @@ server_alive_check(void) | |||
615 | * one of the file descriptors). | 504 | * one of the file descriptors). |
616 | */ | 505 | */ |
617 | static void | 506 | static void |
618 | client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, | 507 | client_wait_until_can_do_something(struct ssh *ssh, |
508 | fd_set **readsetp, fd_set **writesetp, | ||
619 | int *maxfdp, u_int *nallocp, int rekeying) | 509 | int *maxfdp, u_int *nallocp, int rekeying) |
620 | { | 510 | { |
621 | struct timeval tv, *tvp; | 511 | struct timeval tv, *tvp; |
@@ -624,40 +514,20 @@ client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, | |||
624 | int ret; | 514 | int ret; |
625 | 515 | ||
626 | /* Add any selections by the channel mechanism. */ | 516 | /* Add any selections by the channel mechanism. */ |
627 | channel_prepare_select(readsetp, writesetp, maxfdp, nallocp, | 517 | channel_prepare_select(active_state, readsetp, writesetp, maxfdp, |
628 | &minwait_secs, rekeying); | 518 | nallocp, &minwait_secs); |
629 | 519 | ||
630 | if (!compat20) { | 520 | /* channel_prepare_select could have closed the last channel */ |
631 | /* Read from the connection, unless our buffers are full. */ | 521 | if (session_closed && !channel_still_open(ssh) && |
632 | if (buffer_len(&stdout_buffer) < buffer_high && | 522 | !packet_have_data_to_write()) { |
633 | buffer_len(&stderr_buffer) < buffer_high && | 523 | /* clear mask since we did not call select() */ |
634 | channel_not_very_much_buffered_data()) | 524 | memset(*readsetp, 0, *nallocp); |
635 | FD_SET(connection_in, *readsetp); | 525 | memset(*writesetp, 0, *nallocp); |
636 | /* | 526 | return; |
637 | * Read from stdin, unless we have seen EOF or have very much | ||
638 | * buffered data to send to the server. | ||
639 | */ | ||
640 | if (!stdin_eof && packet_not_very_much_data_to_write()) | ||
641 | FD_SET(fileno(stdin), *readsetp); | ||
642 | |||
643 | /* Select stdout/stderr if have data in buffer. */ | ||
644 | if (buffer_len(&stdout_buffer) > 0) | ||
645 | FD_SET(fileno(stdout), *writesetp); | ||
646 | if (buffer_len(&stderr_buffer) > 0) | ||
647 | FD_SET(fileno(stderr), *writesetp); | ||
648 | } else { | ||
649 | /* channel_prepare_select could have closed the last channel */ | ||
650 | if (session_closed && !channel_still_open() && | ||
651 | !packet_have_data_to_write()) { | ||
652 | /* clear mask since we did not call select() */ | ||
653 | memset(*readsetp, 0, *nallocp); | ||
654 | memset(*writesetp, 0, *nallocp); | ||
655 | return; | ||
656 | } else { | ||
657 | FD_SET(connection_in, *readsetp); | ||
658 | } | ||
659 | } | 527 | } |
660 | 528 | ||
529 | FD_SET(connection_in, *readsetp); | ||
530 | |||
661 | /* Select server connection if have data to write to the server. */ | 531 | /* Select server connection if have data to write to the server. */ |
662 | if (packet_have_data_to_write()) | 532 | if (packet_have_data_to_write()) |
663 | FD_SET(connection_out, *writesetp); | 533 | FD_SET(connection_out, *writesetp); |
@@ -669,13 +539,13 @@ client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, | |||
669 | */ | 539 | */ |
670 | 540 | ||
671 | timeout_secs = INT_MAX; /* we use INT_MAX to mean no timeout */ | 541 | timeout_secs = INT_MAX; /* we use INT_MAX to mean no timeout */ |
672 | if (options.server_alive_interval > 0 && compat20) { | 542 | if (options.server_alive_interval > 0) { |
673 | timeout_secs = options.server_alive_interval; | 543 | timeout_secs = options.server_alive_interval; |
674 | server_alive_time = now + options.server_alive_interval; | 544 | server_alive_time = now + options.server_alive_interval; |
675 | } | 545 | } |
676 | if (options.rekey_interval > 0 && compat20 && !rekeying) | 546 | if (options.rekey_interval > 0 && !rekeying) |
677 | timeout_secs = MINIMUM(timeout_secs, packet_get_rekey_timeout()); | 547 | timeout_secs = MINIMUM(timeout_secs, packet_get_rekey_timeout()); |
678 | set_control_persist_exit_time(); | 548 | set_control_persist_exit_time(ssh); |
679 | if (control_persist_exit_time > 0) { | 549 | if (control_persist_exit_time > 0) { |
680 | timeout_secs = MINIMUM(timeout_secs, | 550 | timeout_secs = MINIMUM(timeout_secs, |
681 | control_persist_exit_time - now); | 551 | control_persist_exit_time - now); |
@@ -734,13 +604,9 @@ client_suspend_self(Buffer *bin, Buffer *bout, Buffer *berr) | |||
734 | 604 | ||
735 | leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE); | 605 | leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE); |
736 | 606 | ||
737 | /* | 607 | sshbuf_reset(bin); |
738 | * Free (and clear) the buffer to reduce the amount of data that gets | 608 | sshbuf_reset(bout); |
739 | * written to swap. | 609 | sshbuf_reset(berr); |
740 | */ | ||
741 | buffer_free(bin); | ||
742 | buffer_free(bout); | ||
743 | buffer_free(berr); | ||
744 | 610 | ||
745 | /* Send the suspend signal to the program itself. */ | 611 | /* Send the suspend signal to the program itself. */ |
746 | kill(getpid(), SIGTSTP); | 612 | kill(getpid(), SIGTSTP); |
@@ -748,11 +614,6 @@ client_suspend_self(Buffer *bin, Buffer *bout, Buffer *berr) | |||
748 | /* Reset window sizes in case they have changed */ | 614 | /* Reset window sizes in case they have changed */ |
749 | received_window_change_signal = 1; | 615 | received_window_change_signal = 1; |
750 | 616 | ||
751 | /* OK, we have been continued by the user. Reinitialize buffers. */ | ||
752 | buffer_init(bin); | ||
753 | buffer_init(bout); | ||
754 | buffer_init(berr); | ||
755 | |||
756 | enter_raw_mode(options.request_tty == REQUEST_TTY_FORCE); | 617 | enter_raw_mode(options.request_tty == REQUEST_TTY_FORCE); |
757 | } | 618 | } |
758 | 619 | ||
@@ -806,7 +667,7 @@ client_process_net_input(fd_set *readset) | |||
806 | } | 667 | } |
807 | 668 | ||
808 | static void | 669 | static void |
809 | client_status_confirm(int type, Channel *c, void *ctx) | 670 | client_status_confirm(struct ssh *ssh, int type, Channel *c, void *ctx) |
810 | { | 671 | { |
811 | struct channel_reply_ctx *cr = (struct channel_reply_ctx *)ctx; | 672 | struct channel_reply_ctx *cr = (struct channel_reply_ctx *)ctx; |
812 | char errmsg[256]; | 673 | char errmsg[256]; |
@@ -845,8 +706,7 @@ client_status_confirm(int type, Channel *c, void *ctx) | |||
845 | * their stderr. | 706 | * their stderr. |
846 | */ | 707 | */ |
847 | if (tochan) { | 708 | if (tochan) { |
848 | buffer_append(&c->extended, errmsg, | 709 | buffer_append(c->extended, errmsg, strlen(errmsg)); |
849 | strlen(errmsg)); | ||
850 | } else | 710 | } else |
851 | error("%s", errmsg); | 711 | error("%s", errmsg); |
852 | if (cr->action == CONFIRM_TTY) { | 712 | if (cr->action == CONFIRM_TTY) { |
@@ -857,23 +717,23 @@ client_status_confirm(int type, Channel *c, void *ctx) | |||
857 | if (c->self == session_ident) | 717 | if (c->self == session_ident) |
858 | leave_raw_mode(0); | 718 | leave_raw_mode(0); |
859 | else | 719 | else |
860 | mux_tty_alloc_failed(c); | 720 | mux_tty_alloc_failed(ssh, c); |
861 | } else if (cr->action == CONFIRM_CLOSE) { | 721 | } else if (cr->action == CONFIRM_CLOSE) { |
862 | chan_read_failed(c); | 722 | chan_read_failed(ssh, c); |
863 | chan_write_failed(c); | 723 | chan_write_failed(ssh, c); |
864 | } | 724 | } |
865 | } | 725 | } |
866 | free(cr); | 726 | free(cr); |
867 | } | 727 | } |
868 | 728 | ||
869 | static void | 729 | static void |
870 | client_abandon_status_confirm(Channel *c, void *ctx) | 730 | client_abandon_status_confirm(struct ssh *ssh, Channel *c, void *ctx) |
871 | { | 731 | { |
872 | free(ctx); | 732 | free(ctx); |
873 | } | 733 | } |
874 | 734 | ||
875 | void | 735 | void |
876 | client_expect_confirm(int id, const char *request, | 736 | client_expect_confirm(struct ssh *ssh, int id, const char *request, |
877 | enum confirm_action action) | 737 | enum confirm_action action) |
878 | { | 738 | { |
879 | struct channel_reply_ctx *cr = xcalloc(1, sizeof(*cr)); | 739 | struct channel_reply_ctx *cr = xcalloc(1, sizeof(*cr)); |
@@ -881,7 +741,7 @@ client_expect_confirm(int id, const char *request, | |||
881 | cr->request_type = request; | 741 | cr->request_type = request; |
882 | cr->action = action; | 742 | cr->action = action; |
883 | 743 | ||
884 | channel_register_status_confirm(id, client_status_confirm, | 744 | channel_register_status_confirm(ssh, id, client_status_confirm, |
885 | client_abandon_status_confirm, cr); | 745 | client_abandon_status_confirm, cr); |
886 | } | 746 | } |
887 | 747 | ||
@@ -907,7 +767,7 @@ client_register_global_confirm(global_confirm_cb *cb, void *ctx) | |||
907 | } | 767 | } |
908 | 768 | ||
909 | static void | 769 | static void |
910 | process_cmdline(void) | 770 | process_cmdline(struct ssh *ssh) |
911 | { | 771 | { |
912 | void (*handler)(int); | 772 | void (*handler)(int); |
913 | char *s, *cmd; | 773 | char *s, *cmd; |
@@ -970,11 +830,6 @@ process_cmdline(void) | |||
970 | goto out; | 830 | goto out; |
971 | } | 831 | } |
972 | 832 | ||
973 | if (delete && !compat20) { | ||
974 | logit("Not supported for SSH protocol version 1."); | ||
975 | goto out; | ||
976 | } | ||
977 | |||
978 | while (isspace((u_char)*++s)) | 833 | while (isspace((u_char)*++s)) |
979 | ; | 834 | ; |
980 | 835 | ||
@@ -986,12 +841,12 @@ process_cmdline(void) | |||
986 | goto out; | 841 | goto out; |
987 | } | 842 | } |
988 | if (remote) | 843 | if (remote) |
989 | ok = channel_request_rforward_cancel(&fwd) == 0; | 844 | ok = channel_request_rforward_cancel(ssh, &fwd) == 0; |
990 | else if (dynamic) | 845 | else if (dynamic) |
991 | ok = channel_cancel_lport_listener(&fwd, | 846 | ok = channel_cancel_lport_listener(ssh, &fwd, |
992 | 0, &options.fwd_opts) > 0; | 847 | 0, &options.fwd_opts) > 0; |
993 | else | 848 | else |
994 | ok = channel_cancel_lport_listener(&fwd, | 849 | ok = channel_cancel_lport_listener(ssh, &fwd, |
995 | CHANNEL_CANCEL_PORT_STATIC, | 850 | CHANNEL_CANCEL_PORT_STATIC, |
996 | &options.fwd_opts) > 0; | 851 | &options.fwd_opts) > 0; |
997 | if (!ok) { | 852 | if (!ok) { |
@@ -1005,13 +860,13 @@ process_cmdline(void) | |||
1005 | goto out; | 860 | goto out; |
1006 | } | 861 | } |
1007 | if (local || dynamic) { | 862 | if (local || dynamic) { |
1008 | if (!channel_setup_local_fwd_listener(&fwd, | 863 | if (!channel_setup_local_fwd_listener(ssh, &fwd, |
1009 | &options.fwd_opts)) { | 864 | &options.fwd_opts)) { |
1010 | logit("Port forwarding failed."); | 865 | logit("Port forwarding failed."); |
1011 | goto out; | 866 | goto out; |
1012 | } | 867 | } |
1013 | } else { | 868 | } else { |
1014 | if (channel_request_remote_forwarding(&fwd) < 0) { | 869 | if (channel_request_remote_forwarding(ssh, &fwd) < 0) { |
1015 | logit("Port forwarding failed."); | 870 | logit("Port forwarding failed."); |
1016 | goto out; | 871 | goto out; |
1017 | } | 872 | } |
@@ -1031,10 +886,9 @@ out: | |||
1031 | 886 | ||
1032 | /* reasons to suppress output of an escape command in help output */ | 887 | /* reasons to suppress output of an escape command in help output */ |
1033 | #define SUPPRESS_NEVER 0 /* never suppress, always show */ | 888 | #define SUPPRESS_NEVER 0 /* never suppress, always show */ |
1034 | #define SUPPRESS_PROTO1 1 /* don't show in protocol 1 sessions */ | 889 | #define SUPPRESS_MUXCLIENT 1 /* don't show in mux client sessions */ |
1035 | #define SUPPRESS_MUXCLIENT 2 /* don't show in mux client sessions */ | 890 | #define SUPPRESS_MUXMASTER 2 /* don't show in mux master sessions */ |
1036 | #define SUPPRESS_MUXMASTER 4 /* don't show in mux master sessions */ | 891 | #define SUPPRESS_SYSLOG 4 /* don't show when logging to syslog */ |
1037 | #define SUPPRESS_SYSLOG 8 /* don't show when logging to syslog */ | ||
1038 | struct escape_help_text { | 892 | struct escape_help_text { |
1039 | const char *cmd; | 893 | const char *cmd; |
1040 | const char *text; | 894 | const char *text; |
@@ -1044,9 +898,9 @@ static struct escape_help_text esc_txt[] = { | |||
1044 | {".", "terminate session", SUPPRESS_MUXMASTER}, | 898 | {".", "terminate session", SUPPRESS_MUXMASTER}, |
1045 | {".", "terminate connection (and any multiplexed sessions)", | 899 | {".", "terminate connection (and any multiplexed sessions)", |
1046 | SUPPRESS_MUXCLIENT}, | 900 | SUPPRESS_MUXCLIENT}, |
1047 | {"B", "send a BREAK to the remote system", SUPPRESS_PROTO1}, | 901 | {"B", "send a BREAK to the remote system", SUPPRESS_NEVER}, |
1048 | {"C", "open a command line", SUPPRESS_MUXCLIENT}, | 902 | {"C", "open a command line", SUPPRESS_MUXCLIENT}, |
1049 | {"R", "request rekey", SUPPRESS_PROTO1}, | 903 | {"R", "request rekey", SUPPRESS_NEVER}, |
1050 | {"V/v", "decrease/increase verbosity (LogLevel)", SUPPRESS_MUXCLIENT}, | 904 | {"V/v", "decrease/increase verbosity (LogLevel)", SUPPRESS_MUXCLIENT}, |
1051 | {"^Z", "suspend ssh", SUPPRESS_MUXCLIENT}, | 905 | {"^Z", "suspend ssh", SUPPRESS_MUXCLIENT}, |
1052 | {"#", "list forwarded connections", SUPPRESS_NEVER}, | 906 | {"#", "list forwarded connections", SUPPRESS_NEVER}, |
@@ -1056,8 +910,7 @@ static struct escape_help_text esc_txt[] = { | |||
1056 | }; | 910 | }; |
1057 | 911 | ||
1058 | static void | 912 | static void |
1059 | print_escape_help(Buffer *b, int escape_char, int protocol2, int mux_client, | 913 | print_escape_help(Buffer *b, int escape_char, int mux_client, int using_stderr) |
1060 | int using_stderr) | ||
1061 | { | 914 | { |
1062 | unsigned int i, suppress_flags; | 915 | unsigned int i, suppress_flags; |
1063 | char string[1024]; | 916 | char string[1024]; |
@@ -1066,7 +919,7 @@ print_escape_help(Buffer *b, int escape_char, int protocol2, int mux_client, | |||
1066 | "Supported escape sequences:\r\n", escape_char); | 919 | "Supported escape sequences:\r\n", escape_char); |
1067 | buffer_append(b, string, strlen(string)); | 920 | buffer_append(b, string, strlen(string)); |
1068 | 921 | ||
1069 | suppress_flags = (protocol2 ? 0 : SUPPRESS_PROTO1) | | 922 | suppress_flags = |
1070 | (mux_client ? SUPPRESS_MUXCLIENT : 0) | | 923 | (mux_client ? SUPPRESS_MUXCLIENT : 0) | |
1071 | (mux_client ? 0 : SUPPRESS_MUXMASTER) | | 924 | (mux_client ? 0 : SUPPRESS_MUXMASTER) | |
1072 | (using_stderr ? 0 : SUPPRESS_SYSLOG); | 925 | (using_stderr ? 0 : SUPPRESS_SYSLOG); |
@@ -1087,10 +940,11 @@ print_escape_help(Buffer *b, int escape_char, int protocol2, int mux_client, | |||
1087 | } | 940 | } |
1088 | 941 | ||
1089 | /* | 942 | /* |
1090 | * Process the characters one by one, call with c==NULL for proto1 case. | 943 | * Process the characters one by one. |
1091 | */ | 944 | */ |
1092 | static int | 945 | static int |
1093 | process_escapes(Channel *c, Buffer *bin, Buffer *bout, Buffer *berr, | 946 | process_escapes(struct ssh *ssh, Channel *c, |
947 | Buffer *bin, Buffer *bout, Buffer *berr, | ||
1094 | char *buf, int len) | 948 | char *buf, int len) |
1095 | { | 949 | { |
1096 | char string[1024]; | 950 | char string[1024]; |
@@ -1099,19 +953,11 @@ process_escapes(Channel *c, Buffer *bin, Buffer *bout, Buffer *berr, | |||
1099 | u_int i; | 953 | u_int i; |
1100 | u_char ch; | 954 | u_char ch; |
1101 | char *s; | 955 | char *s; |
1102 | int *escape_pendingp, escape_char; | 956 | struct escape_filter_ctx *efc = c->filter_ctx == NULL ? |
1103 | struct escape_filter_ctx *efc; | 957 | NULL : (struct escape_filter_ctx *)c->filter_ctx; |
1104 | 958 | ||
1105 | if (c == NULL) { | 959 | if (c->filter_ctx == NULL) |
1106 | escape_pendingp = &escape_pending1; | 960 | return 0; |
1107 | escape_char = escape_char1; | ||
1108 | } else { | ||
1109 | if (c->filter_ctx == NULL) | ||
1110 | return 0; | ||
1111 | efc = (struct escape_filter_ctx *)c->filter_ctx; | ||
1112 | escape_pendingp = &efc->escape_pending; | ||
1113 | escape_char = efc->escape_char; | ||
1114 | } | ||
1115 | 961 | ||
1116 | if (len <= 0) | 962 | if (len <= 0) |
1117 | return (0); | 963 | return (0); |
@@ -1120,27 +966,29 @@ process_escapes(Channel *c, Buffer *bin, Buffer *bout, Buffer *berr, | |||
1120 | /* Get one character at a time. */ | 966 | /* Get one character at a time. */ |
1121 | ch = buf[i]; | 967 | ch = buf[i]; |
1122 | 968 | ||
1123 | if (*escape_pendingp) { | 969 | if (efc->escape_pending) { |
1124 | /* We have previously seen an escape character. */ | 970 | /* We have previously seen an escape character. */ |
1125 | /* Clear the flag now. */ | 971 | /* Clear the flag now. */ |
1126 | *escape_pendingp = 0; | 972 | efc->escape_pending = 0; |
1127 | 973 | ||
1128 | /* Process the escaped character. */ | 974 | /* Process the escaped character. */ |
1129 | switch (ch) { | 975 | switch (ch) { |
1130 | case '.': | 976 | case '.': |
1131 | /* Terminate the connection. */ | 977 | /* Terminate the connection. */ |
1132 | snprintf(string, sizeof string, "%c.\r\n", | 978 | snprintf(string, sizeof string, "%c.\r\n", |
1133 | escape_char); | 979 | efc->escape_char); |
1134 | buffer_append(berr, string, strlen(string)); | 980 | buffer_append(berr, string, strlen(string)); |
1135 | 981 | ||
1136 | if (c && c->ctl_chan != -1) { | 982 | if (c && c->ctl_chan != -1) { |
1137 | chan_read_failed(c); | 983 | chan_read_failed(ssh, c); |
1138 | chan_write_failed(c); | 984 | chan_write_failed(ssh, c); |
1139 | if (c->detach_user) | 985 | if (c->detach_user) { |
1140 | c->detach_user(c->self, NULL); | 986 | c->detach_user(ssh, |
987 | c->self, NULL); | ||
988 | } | ||
1141 | c->type = SSH_CHANNEL_ABANDONED; | 989 | c->type = SSH_CHANNEL_ABANDONED; |
1142 | buffer_clear(&c->input); | 990 | buffer_clear(c->input); |
1143 | chan_ibuf_empty(c); | 991 | chan_ibuf_empty(ssh, c); |
1144 | return 0; | 992 | return 0; |
1145 | } else | 993 | } else |
1146 | quit_pending = 1; | 994 | quit_pending = 1; |
@@ -1158,14 +1006,14 @@ process_escapes(Channel *c, Buffer *bin, Buffer *bout, Buffer *berr, | |||
1158 | snprintf(string, sizeof string, | 1006 | snprintf(string, sizeof string, |
1159 | "%c%s escape not available to " | 1007 | "%c%s escape not available to " |
1160 | "multiplexed sessions\r\n", | 1008 | "multiplexed sessions\r\n", |
1161 | escape_char, b); | 1009 | efc->escape_char, b); |
1162 | buffer_append(berr, string, | 1010 | buffer_append(berr, string, |
1163 | strlen(string)); | 1011 | strlen(string)); |
1164 | continue; | 1012 | continue; |
1165 | } | 1013 | } |
1166 | /* Suspend the program. Inform the user */ | 1014 | /* Suspend the program. Inform the user */ |
1167 | snprintf(string, sizeof string, | 1015 | snprintf(string, sizeof string, |
1168 | "%c^Z [suspend ssh]\r\n", escape_char); | 1016 | "%c^Z [suspend ssh]\r\n", efc->escape_char); |
1169 | buffer_append(berr, string, strlen(string)); | 1017 | buffer_append(berr, string, strlen(string)); |
1170 | 1018 | ||
1171 | /* Restore terminal modes and suspend. */ | 1019 | /* Restore terminal modes and suspend. */ |
@@ -1175,26 +1023,20 @@ process_escapes(Channel *c, Buffer *bin, Buffer *bout, Buffer *berr, | |||
1175 | continue; | 1023 | continue; |
1176 | 1024 | ||
1177 | case 'B': | 1025 | case 'B': |
1178 | if (compat20) { | 1026 | snprintf(string, sizeof string, |
1179 | snprintf(string, sizeof string, | 1027 | "%cB\r\n", efc->escape_char); |
1180 | "%cB\r\n", escape_char); | 1028 | buffer_append(berr, string, strlen(string)); |
1181 | buffer_append(berr, string, | 1029 | channel_request_start(ssh, c->self, "break", 0); |
1182 | strlen(string)); | 1030 | packet_put_int(1000); |
1183 | channel_request_start(c->self, | 1031 | packet_send(); |
1184 | "break", 0); | ||
1185 | packet_put_int(1000); | ||
1186 | packet_send(); | ||
1187 | } | ||
1188 | continue; | 1032 | continue; |
1189 | 1033 | ||
1190 | case 'R': | 1034 | case 'R': |
1191 | if (compat20) { | 1035 | if (datafellows & SSH_BUG_NOREKEY) |
1192 | if (datafellows & SSH_BUG_NOREKEY) | 1036 | logit("Server does not " |
1193 | logit("Server does not " | 1037 | "support re-keying"); |
1194 | "support re-keying"); | 1038 | else |
1195 | else | 1039 | need_rekeying = 1; |
1196 | need_rekeying = 1; | ||
1197 | } | ||
1198 | continue; | 1040 | continue; |
1199 | 1041 | ||
1200 | case 'V': | 1042 | case 'V': |
@@ -1205,7 +1047,7 @@ process_escapes(Channel *c, Buffer *bin, Buffer *bout, Buffer *berr, | |||
1205 | if (!log_is_on_stderr()) { | 1047 | if (!log_is_on_stderr()) { |
1206 | snprintf(string, sizeof string, | 1048 | snprintf(string, sizeof string, |
1207 | "%c%c [Logging to syslog]\r\n", | 1049 | "%c%c [Logging to syslog]\r\n", |
1208 | escape_char, ch); | 1050 | efc->escape_char, ch); |
1209 | buffer_append(berr, string, | 1051 | buffer_append(berr, string, |
1210 | strlen(string)); | 1052 | strlen(string)); |
1211 | continue; | 1053 | continue; |
@@ -1217,7 +1059,8 @@ process_escapes(Channel *c, Buffer *bin, Buffer *bout, Buffer *berr, | |||
1217 | SYSLOG_LEVEL_DEBUG3) | 1059 | SYSLOG_LEVEL_DEBUG3) |
1218 | log_change_level(++options.log_level); | 1060 | log_change_level(++options.log_level); |
1219 | snprintf(string, sizeof string, | 1061 | snprintf(string, sizeof string, |
1220 | "%c%c [LogLevel %s]\r\n", escape_char, ch, | 1062 | "%c%c [LogLevel %s]\r\n", |
1063 | efc->escape_char, ch, | ||
1221 | log_level_name(options.log_level)); | 1064 | log_level_name(options.log_level)); |
1222 | buffer_append(berr, string, strlen(string)); | 1065 | buffer_append(berr, string, strlen(string)); |
1223 | continue; | 1066 | continue; |
@@ -1235,10 +1078,10 @@ process_escapes(Channel *c, Buffer *bin, Buffer *bout, Buffer *berr, | |||
1235 | options.request_tty == REQUEST_TTY_FORCE); | 1078 | options.request_tty == REQUEST_TTY_FORCE); |
1236 | 1079 | ||
1237 | /* Stop listening for new connections. */ | 1080 | /* Stop listening for new connections. */ |
1238 | channel_stop_listening(); | 1081 | channel_stop_listening(ssh); |
1239 | 1082 | ||
1240 | snprintf(string, sizeof string, | 1083 | snprintf(string, sizeof string, |
1241 | "%c& [backgrounded]\n", escape_char); | 1084 | "%c& [backgrounded]\n", efc->escape_char); |
1242 | buffer_append(berr, string, strlen(string)); | 1085 | buffer_append(berr, string, strlen(string)); |
1243 | 1086 | ||
1244 | /* Fork into background. */ | 1087 | /* Fork into background. */ |
@@ -1252,39 +1095,20 @@ process_escapes(Channel *c, Buffer *bin, Buffer *bout, Buffer *berr, | |||
1252 | exit(0); | 1095 | exit(0); |
1253 | } | 1096 | } |
1254 | /* The child continues serving connections. */ | 1097 | /* The child continues serving connections. */ |
1255 | if (compat20) { | 1098 | buffer_append(bin, "\004", 1); |
1256 | buffer_append(bin, "\004", 1); | 1099 | /* fake EOF on stdin */ |
1257 | /* fake EOF on stdin */ | 1100 | return -1; |
1258 | return -1; | ||
1259 | } else if (!stdin_eof) { | ||
1260 | /* | ||
1261 | * Sending SSH_CMSG_EOF alone does not | ||
1262 | * always appear to be enough. So we | ||
1263 | * try to send an EOF character first. | ||
1264 | */ | ||
1265 | packet_start(SSH_CMSG_STDIN_DATA); | ||
1266 | packet_put_string("\004", 1); | ||
1267 | packet_send(); | ||
1268 | /* Close stdin. */ | ||
1269 | stdin_eof = 1; | ||
1270 | if (buffer_len(bin) == 0) { | ||
1271 | packet_start(SSH_CMSG_EOF); | ||
1272 | packet_send(); | ||
1273 | } | ||
1274 | } | ||
1275 | continue; | ||
1276 | |||
1277 | case '?': | 1101 | case '?': |
1278 | print_escape_help(berr, escape_char, compat20, | 1102 | print_escape_help(berr, efc->escape_char, |
1279 | (c && c->ctl_chan != -1), | 1103 | (c && c->ctl_chan != -1), |
1280 | log_is_on_stderr()); | 1104 | log_is_on_stderr()); |
1281 | continue; | 1105 | continue; |
1282 | 1106 | ||
1283 | case '#': | 1107 | case '#': |
1284 | snprintf(string, sizeof string, "%c#\r\n", | 1108 | snprintf(string, sizeof string, "%c#\r\n", |
1285 | escape_char); | 1109 | efc->escape_char); |
1286 | buffer_append(berr, string, strlen(string)); | 1110 | buffer_append(berr, string, strlen(string)); |
1287 | s = channel_open_message(); | 1111 | s = channel_open_message(ssh); |
1288 | buffer_append(berr, s, strlen(s)); | 1112 | buffer_append(berr, s, strlen(s)); |
1289 | free(s); | 1113 | free(s); |
1290 | continue; | 1114 | continue; |
@@ -1292,12 +1116,12 @@ process_escapes(Channel *c, Buffer *bin, Buffer *bout, Buffer *berr, | |||
1292 | case 'C': | 1116 | case 'C': |
1293 | if (c && c->ctl_chan != -1) | 1117 | if (c && c->ctl_chan != -1) |
1294 | goto noescape; | 1118 | goto noescape; |
1295 | process_cmdline(); | 1119 | process_cmdline(ssh); |
1296 | continue; | 1120 | continue; |
1297 | 1121 | ||
1298 | default: | 1122 | default: |
1299 | if (ch != escape_char) { | 1123 | if (ch != efc->escape_char) { |
1300 | buffer_put_char(bin, escape_char); | 1124 | buffer_put_char(bin, efc->escape_char); |
1301 | bytes++; | 1125 | bytes++; |
1302 | } | 1126 | } |
1303 | /* Escaped characters fall through here */ | 1127 | /* Escaped characters fall through here */ |
@@ -1308,12 +1132,12 @@ process_escapes(Channel *c, Buffer *bin, Buffer *bout, Buffer *berr, | |||
1308 | * The previous character was not an escape char. | 1132 | * The previous character was not an escape char. |
1309 | * Check if this is an escape. | 1133 | * Check if this is an escape. |
1310 | */ | 1134 | */ |
1311 | if (last_was_cr && ch == escape_char) { | 1135 | if (last_was_cr && ch == efc->escape_char) { |
1312 | /* | 1136 | /* |
1313 | * It is. Set the flag and continue to | 1137 | * It is. Set the flag and continue to |
1314 | * next character. | 1138 | * next character. |
1315 | */ | 1139 | */ |
1316 | *escape_pendingp = 1; | 1140 | efc->escape_pending = 1; |
1317 | continue; | 1141 | continue; |
1318 | } | 1142 | } |
1319 | } | 1143 | } |
@@ -1329,115 +1153,6 @@ process_escapes(Channel *c, Buffer *bin, Buffer *bout, Buffer *berr, | |||
1329 | return bytes; | 1153 | return bytes; |
1330 | } | 1154 | } |
1331 | 1155 | ||
1332 | static void | ||
1333 | client_process_input(fd_set *readset) | ||
1334 | { | ||
1335 | int len; | ||
1336 | char buf[SSH_IOBUFSZ]; | ||
1337 | |||
1338 | /* Read input from stdin. */ | ||
1339 | if (FD_ISSET(fileno(stdin), readset)) { | ||
1340 | /* Read as much as possible. */ | ||
1341 | len = read(fileno(stdin), buf, sizeof(buf)); | ||
1342 | if (len < 0 && | ||
1343 | (errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK)) | ||
1344 | return; /* we'll try again later */ | ||
1345 | if (len <= 0) { | ||
1346 | /* | ||
1347 | * Received EOF or error. They are treated | ||
1348 | * similarly, except that an error message is printed | ||
1349 | * if it was an error condition. | ||
1350 | */ | ||
1351 | if (len < 0) { | ||
1352 | snprintf(buf, sizeof buf, "read: %.100s\r\n", | ||
1353 | strerror(errno)); | ||
1354 | buffer_append(&stderr_buffer, buf, strlen(buf)); | ||
1355 | } | ||
1356 | /* Mark that we have seen EOF. */ | ||
1357 | stdin_eof = 1; | ||
1358 | /* | ||
1359 | * Send an EOF message to the server unless there is | ||
1360 | * data in the buffer. If there is data in the | ||
1361 | * buffer, no message will be sent now. Code | ||
1362 | * elsewhere will send the EOF when the buffer | ||
1363 | * becomes empty if stdin_eof is set. | ||
1364 | */ | ||
1365 | if (buffer_len(&stdin_buffer) == 0) { | ||
1366 | packet_start(SSH_CMSG_EOF); | ||
1367 | packet_send(); | ||
1368 | } | ||
1369 | } else if (escape_char1 == SSH_ESCAPECHAR_NONE) { | ||
1370 | /* | ||
1371 | * Normal successful read, and no escape character. | ||
1372 | * Just append the data to buffer. | ||
1373 | */ | ||
1374 | buffer_append(&stdin_buffer, buf, len); | ||
1375 | } else { | ||
1376 | /* | ||
1377 | * Normal, successful read. But we have an escape | ||
1378 | * character and have to process the characters one | ||
1379 | * by one. | ||
1380 | */ | ||
1381 | if (process_escapes(NULL, &stdin_buffer, | ||
1382 | &stdout_buffer, &stderr_buffer, buf, len) == -1) | ||
1383 | return; | ||
1384 | } | ||
1385 | } | ||
1386 | } | ||
1387 | |||
1388 | static void | ||
1389 | client_process_output(fd_set *writeset) | ||
1390 | { | ||
1391 | int len; | ||
1392 | char buf[100]; | ||
1393 | |||
1394 | /* Write buffered output to stdout. */ | ||
1395 | if (FD_ISSET(fileno(stdout), writeset)) { | ||
1396 | /* Write as much data as possible. */ | ||
1397 | len = write(fileno(stdout), buffer_ptr(&stdout_buffer), | ||
1398 | buffer_len(&stdout_buffer)); | ||
1399 | if (len <= 0) { | ||
1400 | if (errno == EINTR || errno == EAGAIN || | ||
1401 | errno == EWOULDBLOCK) | ||
1402 | len = 0; | ||
1403 | else { | ||
1404 | /* | ||
1405 | * An error or EOF was encountered. Put an | ||
1406 | * error message to stderr buffer. | ||
1407 | */ | ||
1408 | snprintf(buf, sizeof buf, | ||
1409 | "write stdout: %.50s\r\n", strerror(errno)); | ||
1410 | buffer_append(&stderr_buffer, buf, strlen(buf)); | ||
1411 | quit_pending = 1; | ||
1412 | return; | ||
1413 | } | ||
1414 | } | ||
1415 | /* Consume printed data from the buffer. */ | ||
1416 | buffer_consume(&stdout_buffer, len); | ||
1417 | } | ||
1418 | /* Write buffered output to stderr. */ | ||
1419 | if (FD_ISSET(fileno(stderr), writeset)) { | ||
1420 | /* Write as much data as possible. */ | ||
1421 | len = write(fileno(stderr), buffer_ptr(&stderr_buffer), | ||
1422 | buffer_len(&stderr_buffer)); | ||
1423 | if (len <= 0) { | ||
1424 | if (errno == EINTR || errno == EAGAIN || | ||
1425 | errno == EWOULDBLOCK) | ||
1426 | len = 0; | ||
1427 | else { | ||
1428 | /* | ||
1429 | * EOF or error, but can't even print | ||
1430 | * error message. | ||
1431 | */ | ||
1432 | quit_pending = 1; | ||
1433 | return; | ||
1434 | } | ||
1435 | } | ||
1436 | /* Consume printed characters from the buffer. */ | ||
1437 | buffer_consume(&stderr_buffer, len); | ||
1438 | } | ||
1439 | } | ||
1440 | |||
1441 | /* | 1156 | /* |
1442 | * Get packets from the connection input buffer, and process them as long as | 1157 | * Get packets from the connection input buffer, and process them as long as |
1443 | * there are packets available. | 1158 | * there are packets available. |
@@ -1453,7 +1168,7 @@ client_process_output(fd_set *writeset) | |||
1453 | static void | 1168 | static void |
1454 | client_process_buffered_input_packets(void) | 1169 | client_process_buffered_input_packets(void) |
1455 | { | 1170 | { |
1456 | dispatch_run(DISPATCH_NONBLOCK, &quit_pending, active_state); | 1171 | ssh_dispatch_run_fatal(active_state, DISPATCH_NONBLOCK, &quit_pending); |
1457 | } | 1172 | } |
1458 | 1173 | ||
1459 | /* scan buf[] for '~' before sending data to the peer */ | 1174 | /* scan buf[] for '~' before sending data to the peer */ |
@@ -1472,25 +1187,25 @@ client_new_escape_filter_ctx(int escape_char) | |||
1472 | 1187 | ||
1473 | /* Free the escape filter context on channel free */ | 1188 | /* Free the escape filter context on channel free */ |
1474 | void | 1189 | void |
1475 | client_filter_cleanup(int cid, void *ctx) | 1190 | client_filter_cleanup(struct ssh *ssh, int cid, void *ctx) |
1476 | { | 1191 | { |
1477 | free(ctx); | 1192 | free(ctx); |
1478 | } | 1193 | } |
1479 | 1194 | ||
1480 | int | 1195 | int |
1481 | client_simple_escape_filter(Channel *c, char *buf, int len) | 1196 | client_simple_escape_filter(struct ssh *ssh, Channel *c, char *buf, int len) |
1482 | { | 1197 | { |
1483 | if (c->extended_usage != CHAN_EXTENDED_WRITE) | 1198 | if (c->extended_usage != CHAN_EXTENDED_WRITE) |
1484 | return 0; | 1199 | return 0; |
1485 | 1200 | ||
1486 | return process_escapes(c, &c->input, &c->output, &c->extended, | 1201 | return process_escapes(ssh, c, c->input, c->output, c->extended, |
1487 | buf, len); | 1202 | buf, len); |
1488 | } | 1203 | } |
1489 | 1204 | ||
1490 | static void | 1205 | static void |
1491 | client_channel_closed(int id, void *arg) | 1206 | client_channel_closed(struct ssh *ssh, int id, void *arg) |
1492 | { | 1207 | { |
1493 | channel_cancel_cleanup(id); | 1208 | channel_cancel_cleanup(ssh, id); |
1494 | session_closed = 1; | 1209 | session_closed = 1; |
1495 | leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE); | 1210 | leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE); |
1496 | } | 1211 | } |
@@ -1501,9 +1216,9 @@ client_channel_closed(int id, void *arg) | |||
1501 | * remote host. If escape_char != SSH_ESCAPECHAR_NONE, it is the character | 1216 | * remote host. If escape_char != SSH_ESCAPECHAR_NONE, it is the character |
1502 | * used as an escape character for terminating or suspending the session. | 1217 | * used as an escape character for terminating or suspending the session. |
1503 | */ | 1218 | */ |
1504 | |||
1505 | int | 1219 | int |
1506 | client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | 1220 | client_loop(struct ssh *ssh, int have_pty, int escape_char_arg, |
1221 | int ssh2_chan_id) | ||
1507 | { | 1222 | { |
1508 | fd_set *readset = NULL, *writeset = NULL; | 1223 | fd_set *readset = NULL, *writeset = NULL; |
1509 | double start_time, total_time; | 1224 | double start_time, total_time; |
@@ -1541,40 +1256,22 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1541 | 1256 | ||
1542 | } else { | 1257 | } else { |
1543 | debug("pledge: network"); | 1258 | debug("pledge: network"); |
1544 | if (pledge("stdio unix inet dns tty", NULL) == -1) | 1259 | if (pledge("stdio unix inet dns proc tty", NULL) == -1) |
1545 | fatal("%s pledge(): %s", __func__, strerror(errno)); | 1260 | fatal("%s pledge(): %s", __func__, strerror(errno)); |
1546 | } | 1261 | } |
1547 | 1262 | ||
1548 | start_time = get_current_time(); | 1263 | start_time = get_current_time(); |
1549 | 1264 | ||
1550 | /* Initialize variables. */ | 1265 | /* Initialize variables. */ |
1551 | escape_pending1 = 0; | ||
1552 | last_was_cr = 1; | 1266 | last_was_cr = 1; |
1553 | exit_status = -1; | 1267 | exit_status = -1; |
1554 | stdin_eof = 0; | ||
1555 | buffer_high = 64 * 1024; | ||
1556 | connection_in = packet_get_connection_in(); | 1268 | connection_in = packet_get_connection_in(); |
1557 | connection_out = packet_get_connection_out(); | 1269 | connection_out = packet_get_connection_out(); |
1558 | max_fd = MAXIMUM(connection_in, connection_out); | 1270 | max_fd = MAXIMUM(connection_in, connection_out); |
1559 | 1271 | ||
1560 | if (!compat20) { | ||
1561 | /* enable nonblocking unless tty */ | ||
1562 | if (!isatty(fileno(stdin))) | ||
1563 | set_nonblock(fileno(stdin)); | ||
1564 | if (!isatty(fileno(stdout))) | ||
1565 | set_nonblock(fileno(stdout)); | ||
1566 | if (!isatty(fileno(stderr))) | ||
1567 | set_nonblock(fileno(stderr)); | ||
1568 | max_fd = MAXIMUM(max_fd, fileno(stdin)); | ||
1569 | max_fd = MAXIMUM(max_fd, fileno(stdout)); | ||
1570 | max_fd = MAXIMUM(max_fd, fileno(stderr)); | ||
1571 | } | ||
1572 | quit_pending = 0; | 1272 | quit_pending = 0; |
1573 | escape_char1 = escape_char_arg; | ||
1574 | 1273 | ||
1575 | /* Initialize buffers. */ | 1274 | /* Initialize buffers. */ |
1576 | buffer_init(&stdin_buffer); | ||
1577 | buffer_init(&stdout_buffer); | ||
1578 | buffer_init(&stderr_buffer); | 1275 | buffer_init(&stderr_buffer); |
1579 | 1276 | ||
1580 | client_init_dispatch(); | 1277 | client_init_dispatch(); |
@@ -1596,22 +1293,17 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1596 | if (have_pty) | 1293 | if (have_pty) |
1597 | enter_raw_mode(options.request_tty == REQUEST_TTY_FORCE); | 1294 | enter_raw_mode(options.request_tty == REQUEST_TTY_FORCE); |
1598 | 1295 | ||
1599 | if (compat20) { | 1296 | session_ident = ssh2_chan_id; |
1600 | session_ident = ssh2_chan_id; | 1297 | if (session_ident != -1) { |
1601 | if (session_ident != -1) { | 1298 | if (escape_char_arg != SSH_ESCAPECHAR_NONE) { |
1602 | if (escape_char_arg != SSH_ESCAPECHAR_NONE) { | 1299 | channel_register_filter(ssh, session_ident, |
1603 | channel_register_filter(session_ident, | 1300 | client_simple_escape_filter, NULL, |
1604 | client_simple_escape_filter, NULL, | 1301 | client_filter_cleanup, |
1605 | client_filter_cleanup, | 1302 | client_new_escape_filter_ctx( |
1606 | client_new_escape_filter_ctx( | 1303 | escape_char_arg)); |
1607 | escape_char_arg)); | ||
1608 | } | ||
1609 | channel_register_cleanup(session_ident, | ||
1610 | client_channel_closed, 0); | ||
1611 | } | 1304 | } |
1612 | } else { | 1305 | channel_register_cleanup(ssh, session_ident, |
1613 | /* Check if we should immediately send eof on stdin. */ | 1306 | client_channel_closed, 0); |
1614 | client_check_initial_eof_on_stdin(); | ||
1615 | } | 1307 | } |
1616 | 1308 | ||
1617 | /* Main loop of the client for the interactive session mode. */ | 1309 | /* Main loop of the client for the interactive session mode. */ |
@@ -1620,38 +1312,31 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1620 | /* Process buffered packets sent by the server. */ | 1312 | /* Process buffered packets sent by the server. */ |
1621 | client_process_buffered_input_packets(); | 1313 | client_process_buffered_input_packets(); |
1622 | 1314 | ||
1623 | if (compat20 && session_closed && !channel_still_open()) | 1315 | if (session_closed && !channel_still_open(ssh)) |
1624 | break; | 1316 | break; |
1625 | 1317 | ||
1626 | if (ssh_packet_is_rekeying(active_state)) { | 1318 | if (ssh_packet_is_rekeying(ssh)) { |
1627 | debug("rekeying in progress"); | 1319 | debug("rekeying in progress"); |
1628 | } else if (need_rekeying) { | 1320 | } else if (need_rekeying) { |
1629 | /* manual rekey request */ | 1321 | /* manual rekey request */ |
1630 | debug("need rekeying"); | 1322 | debug("need rekeying"); |
1631 | if ((r = kex_start_rekex(active_state)) != 0) | 1323 | if ((r = kex_start_rekex(ssh)) != 0) |
1632 | fatal("%s: kex_start_rekex: %s", __func__, | 1324 | fatal("%s: kex_start_rekex: %s", __func__, |
1633 | ssh_err(r)); | 1325 | ssh_err(r)); |
1634 | need_rekeying = 0; | 1326 | need_rekeying = 0; |
1635 | } else { | 1327 | } else { |
1636 | /* | 1328 | /* |
1637 | * Make packets of buffered stdin data, and buffer | ||
1638 | * them for sending to the server. | ||
1639 | */ | ||
1640 | if (!compat20) | ||
1641 | client_make_packets_from_stdin_data(); | ||
1642 | |||
1643 | /* | ||
1644 | * Make packets from buffered channel data, and | 1329 | * Make packets from buffered channel data, and |
1645 | * enqueue them for sending to the server. | 1330 | * enqueue them for sending to the server. |
1646 | */ | 1331 | */ |
1647 | if (packet_not_very_much_data_to_write()) | 1332 | if (packet_not_very_much_data_to_write()) |
1648 | channel_output_poll(); | 1333 | channel_output_poll(ssh); |
1649 | 1334 | ||
1650 | /* | 1335 | /* |
1651 | * Check if the window size has changed, and buffer a | 1336 | * Check if the window size has changed, and buffer a |
1652 | * message about it to the server if so. | 1337 | * message about it to the server if so. |
1653 | */ | 1338 | */ |
1654 | client_check_window_change(); | 1339 | client_check_window_change(ssh); |
1655 | 1340 | ||
1656 | if (quit_pending) | 1341 | if (quit_pending) |
1657 | break; | 1342 | break; |
@@ -1661,15 +1346,15 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1661 | * available on one of the descriptors). | 1346 | * available on one of the descriptors). |
1662 | */ | 1347 | */ |
1663 | max_fd2 = max_fd; | 1348 | max_fd2 = max_fd; |
1664 | client_wait_until_can_do_something(&readset, &writeset, | 1349 | client_wait_until_can_do_something(ssh, &readset, &writeset, |
1665 | &max_fd2, &nalloc, ssh_packet_is_rekeying(active_state)); | 1350 | &max_fd2, &nalloc, ssh_packet_is_rekeying(ssh)); |
1666 | 1351 | ||
1667 | if (quit_pending) | 1352 | if (quit_pending) |
1668 | break; | 1353 | break; |
1669 | 1354 | ||
1670 | /* Do channel operations unless rekeying in progress. */ | 1355 | /* Do channel operations unless rekeying in progress. */ |
1671 | if (!ssh_packet_is_rekeying(active_state)) { | 1356 | if (!ssh_packet_is_rekeying(ssh)) { |
1672 | channel_after_select(readset, writeset); | 1357 | channel_after_select(ssh, readset, writeset); |
1673 | 1358 | ||
1674 | #ifdef GSSAPI | 1359 | #ifdef GSSAPI |
1675 | if (options.gss_renewal_rekey && | 1360 | if (options.gss_renewal_rekey && |
@@ -1686,16 +1371,6 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1686 | if (quit_pending) | 1371 | if (quit_pending) |
1687 | break; | 1372 | break; |
1688 | 1373 | ||
1689 | if (!compat20) { | ||
1690 | /* Buffer data from stdin */ | ||
1691 | client_process_input(readset); | ||
1692 | /* | ||
1693 | * Process output to stdout and stderr. Output to | ||
1694 | * the connection is processed elsewhere (above). | ||
1695 | */ | ||
1696 | client_process_output(writeset); | ||
1697 | } | ||
1698 | |||
1699 | /* | 1374 | /* |
1700 | * Send as much buffered packet data as possible to the | 1375 | * Send as much buffered packet data as possible to the |
1701 | * sender. | 1376 | * sender. |
@@ -1723,16 +1398,14 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1723 | /* Stop watching for window change. */ | 1398 | /* Stop watching for window change. */ |
1724 | signal(SIGWINCH, SIG_DFL); | 1399 | signal(SIGWINCH, SIG_DFL); |
1725 | 1400 | ||
1726 | if (compat20) { | 1401 | packet_start(SSH2_MSG_DISCONNECT); |
1727 | packet_start(SSH2_MSG_DISCONNECT); | 1402 | packet_put_int(SSH2_DISCONNECT_BY_APPLICATION); |
1728 | packet_put_int(SSH2_DISCONNECT_BY_APPLICATION); | 1403 | packet_put_cstring("disconnected by user"); |
1729 | packet_put_cstring("disconnected by user"); | 1404 | packet_put_cstring(""); /* language tag */ |
1730 | packet_put_cstring(""); /* language tag */ | 1405 | packet_send(); |
1731 | packet_send(); | 1406 | packet_write_wait(); |
1732 | packet_write_wait(); | ||
1733 | } | ||
1734 | 1407 | ||
1735 | channel_free_all(); | 1408 | channel_free_all(ssh); |
1736 | 1409 | ||
1737 | if (have_pty) | 1410 | if (have_pty) |
1738 | leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE); | 1411 | leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE); |
@@ -1756,8 +1429,8 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1756 | } | 1429 | } |
1757 | 1430 | ||
1758 | if (received_signal) { | 1431 | if (received_signal) { |
1759 | debug("Killed by signal %d.", (int) received_signal); | 1432 | verbose("Killed by signal %d.", (int) received_signal); |
1760 | cleanup_exit((int) received_signal + 128); | 1433 | cleanup_exit(0); |
1761 | } | 1434 | } |
1762 | 1435 | ||
1763 | /* | 1436 | /* |
@@ -1770,16 +1443,6 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1770 | buffer_append(&stderr_buffer, buf, strlen(buf)); | 1443 | buffer_append(&stderr_buffer, buf, strlen(buf)); |
1771 | } | 1444 | } |
1772 | 1445 | ||
1773 | /* Output any buffered data for stdout. */ | ||
1774 | if (buffer_len(&stdout_buffer) > 0) { | ||
1775 | len = atomicio(vwrite, fileno(stdout), | ||
1776 | buffer_ptr(&stdout_buffer), buffer_len(&stdout_buffer)); | ||
1777 | if (len < 0 || (u_int)len != buffer_len(&stdout_buffer)) | ||
1778 | error("Write failed flushing stdout buffer."); | ||
1779 | else | ||
1780 | buffer_consume(&stdout_buffer, len); | ||
1781 | } | ||
1782 | |||
1783 | /* Output any buffered data for stderr. */ | 1446 | /* Output any buffered data for stderr. */ |
1784 | if (buffer_len(&stderr_buffer) > 0) { | 1447 | if (buffer_len(&stderr_buffer) > 0) { |
1785 | len = atomicio(vwrite, fileno(stderr), | 1448 | len = atomicio(vwrite, fileno(stderr), |
@@ -1792,8 +1455,6 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1792 | 1455 | ||
1793 | /* Clear and free any buffers. */ | 1456 | /* Clear and free any buffers. */ |
1794 | explicit_bzero(buf, sizeof(buf)); | 1457 | explicit_bzero(buf, sizeof(buf)); |
1795 | buffer_free(&stdin_buffer); | ||
1796 | buffer_free(&stdout_buffer); | ||
1797 | buffer_free(&stderr_buffer); | 1458 | buffer_free(&stderr_buffer); |
1798 | 1459 | ||
1799 | /* Report bytes transferred, and transfer rates. */ | 1460 | /* Report bytes transferred, and transfer rates. */ |
@@ -1811,95 +1472,9 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1811 | 1472 | ||
1812 | /*********/ | 1473 | /*********/ |
1813 | 1474 | ||
1814 | static int | ||
1815 | client_input_stdout_data(int type, u_int32_t seq, void *ctxt) | ||
1816 | { | ||
1817 | u_int data_len; | ||
1818 | char *data = packet_get_string(&data_len); | ||
1819 | packet_check_eom(); | ||
1820 | buffer_append(&stdout_buffer, data, data_len); | ||
1821 | explicit_bzero(data, data_len); | ||
1822 | free(data); | ||
1823 | return 0; | ||
1824 | } | ||
1825 | static int | ||
1826 | client_input_stderr_data(int type, u_int32_t seq, void *ctxt) | ||
1827 | { | ||
1828 | u_int data_len; | ||
1829 | char *data = packet_get_string(&data_len); | ||
1830 | packet_check_eom(); | ||
1831 | buffer_append(&stderr_buffer, data, data_len); | ||
1832 | explicit_bzero(data, data_len); | ||
1833 | free(data); | ||
1834 | return 0; | ||
1835 | } | ||
1836 | static int | ||
1837 | client_input_exit_status(int type, u_int32_t seq, void *ctxt) | ||
1838 | { | ||
1839 | exit_status = packet_get_int(); | ||
1840 | packet_check_eom(); | ||
1841 | /* Acknowledge the exit. */ | ||
1842 | packet_start(SSH_CMSG_EXIT_CONFIRMATION); | ||
1843 | packet_send(); | ||
1844 | /* | ||
1845 | * Must wait for packet to be sent since we are | ||
1846 | * exiting the loop. | ||
1847 | */ | ||
1848 | packet_write_wait(); | ||
1849 | /* Flag that we want to exit. */ | ||
1850 | quit_pending = 1; | ||
1851 | return 0; | ||
1852 | } | ||
1853 | |||
1854 | static int | ||
1855 | client_input_agent_open(int type, u_int32_t seq, void *ctxt) | ||
1856 | { | ||
1857 | Channel *c = NULL; | ||
1858 | int r, remote_id, sock; | ||
1859 | |||
1860 | /* Read the remote channel number from the message. */ | ||
1861 | remote_id = packet_get_int(); | ||
1862 | packet_check_eom(); | ||
1863 | |||
1864 | /* | ||
1865 | * Get a connection to the local authentication agent (this may again | ||
1866 | * get forwarded). | ||
1867 | */ | ||
1868 | if ((r = ssh_get_authentication_socket(&sock)) != 0 && | ||
1869 | r != SSH_ERR_AGENT_NOT_PRESENT) | ||
1870 | debug("%s: ssh_get_authentication_socket: %s", | ||
1871 | __func__, ssh_err(r)); | ||
1872 | |||
1873 | |||
1874 | /* | ||
1875 | * If we could not connect the agent, send an error message back to | ||
1876 | * the server. This should never happen unless the agent dies, | ||
1877 | * because authentication forwarding is only enabled if we have an | ||
1878 | * agent. | ||
1879 | */ | ||
1880 | if (sock >= 0) { | ||
1881 | c = channel_new("", SSH_CHANNEL_OPEN, sock, sock, | ||
1882 | -1, 0, 0, 0, "authentication agent connection", 1); | ||
1883 | c->remote_id = remote_id; | ||
1884 | c->force_drain = 1; | ||
1885 | } | ||
1886 | if (c == NULL) { | ||
1887 | packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); | ||
1888 | packet_put_int(remote_id); | ||
1889 | } else { | ||
1890 | /* Send a confirmation to the remote host. */ | ||
1891 | debug("Forwarding authentication connection."); | ||
1892 | packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION); | ||
1893 | packet_put_int(remote_id); | ||
1894 | packet_put_int(c->self); | ||
1895 | } | ||
1896 | packet_send(); | ||
1897 | return 0; | ||
1898 | } | ||
1899 | |||
1900 | static Channel * | 1475 | static Channel * |
1901 | client_request_forwarded_tcpip(const char *request_type, int rchan, | 1476 | client_request_forwarded_tcpip(struct ssh *ssh, const char *request_type, |
1902 | u_int rwindow, u_int rmaxpack) | 1477 | int rchan, u_int rwindow, u_int rmaxpack) |
1903 | { | 1478 | { |
1904 | Channel *c = NULL; | 1479 | Channel *c = NULL; |
1905 | struct sshbuf *b = NULL; | 1480 | struct sshbuf *b = NULL; |
@@ -1917,7 +1492,7 @@ client_request_forwarded_tcpip(const char *request_type, int rchan, | |||
1917 | debug("%s: listen %s port %d, originator %s port %d", __func__, | 1492 | debug("%s: listen %s port %d, originator %s port %d", __func__, |
1918 | listen_address, listen_port, originator_address, originator_port); | 1493 | listen_address, listen_port, originator_address, originator_port); |
1919 | 1494 | ||
1920 | c = channel_connect_by_listen_address(listen_address, listen_port, | 1495 | c = channel_connect_by_listen_address(ssh, listen_address, listen_port, |
1921 | "forwarded-tcpip", originator_address); | 1496 | "forwarded-tcpip", originator_address); |
1922 | 1497 | ||
1923 | if (c != NULL && c->type == SSH_CHANNEL_MUX_CLIENT) { | 1498 | if (c != NULL && c->type == SSH_CHANNEL_MUX_CLIENT) { |
@@ -1936,7 +1511,7 @@ client_request_forwarded_tcpip(const char *request_type, int rchan, | |||
1936 | (r = sshbuf_put_u32(b, listen_port)) != 0 || | 1511 | (r = sshbuf_put_u32(b, listen_port)) != 0 || |
1937 | (r = sshbuf_put_cstring(b, originator_address)) != 0 || | 1512 | (r = sshbuf_put_cstring(b, originator_address)) != 0 || |
1938 | (r = sshbuf_put_u32(b, originator_port)) != 0 || | 1513 | (r = sshbuf_put_u32(b, originator_port)) != 0 || |
1939 | (r = sshbuf_put_stringb(&c->output, b)) != 0) { | 1514 | (r = sshbuf_put_stringb(c->output, b)) != 0) { |
1940 | error("%s: compose for muxclient %s", __func__, | 1515 | error("%s: compose for muxclient %s", __func__, |
1941 | ssh_err(r)); | 1516 | ssh_err(r)); |
1942 | goto out; | 1517 | goto out; |
@@ -1951,7 +1526,8 @@ client_request_forwarded_tcpip(const char *request_type, int rchan, | |||
1951 | } | 1526 | } |
1952 | 1527 | ||
1953 | static Channel * | 1528 | static Channel * |
1954 | client_request_forwarded_streamlocal(const char *request_type, int rchan) | 1529 | client_request_forwarded_streamlocal(struct ssh *ssh, |
1530 | const char *request_type, int rchan) | ||
1955 | { | 1531 | { |
1956 | Channel *c = NULL; | 1532 | Channel *c = NULL; |
1957 | char *listen_path; | 1533 | char *listen_path; |
@@ -1965,14 +1541,14 @@ client_request_forwarded_streamlocal(const char *request_type, int rchan) | |||
1965 | 1541 | ||
1966 | debug("%s: %s", __func__, listen_path); | 1542 | debug("%s: %s", __func__, listen_path); |
1967 | 1543 | ||
1968 | c = channel_connect_by_listen_path(listen_path, | 1544 | c = channel_connect_by_listen_path(ssh, listen_path, |
1969 | "forwarded-streamlocal@openssh.com", "forwarded-streamlocal"); | 1545 | "forwarded-streamlocal@openssh.com", "forwarded-streamlocal"); |
1970 | free(listen_path); | 1546 | free(listen_path); |
1971 | return c; | 1547 | return c; |
1972 | } | 1548 | } |
1973 | 1549 | ||
1974 | static Channel * | 1550 | static Channel * |
1975 | client_request_x11(const char *request_type, int rchan) | 1551 | client_request_x11(struct ssh *ssh, const char *request_type, int rchan) |
1976 | { | 1552 | { |
1977 | Channel *c = NULL; | 1553 | Channel *c = NULL; |
1978 | char *originator; | 1554 | char *originator; |
@@ -2002,10 +1578,10 @@ client_request_x11(const char *request_type, int rchan) | |||
2002 | debug("client_request_x11: request from %s %d", originator, | 1578 | debug("client_request_x11: request from %s %d", originator, |
2003 | originator_port); | 1579 | originator_port); |
2004 | free(originator); | 1580 | free(originator); |
2005 | sock = x11_connect_display(); | 1581 | sock = x11_connect_display(ssh); |
2006 | if (sock < 0) | 1582 | if (sock < 0) |
2007 | return NULL; | 1583 | return NULL; |
2008 | c = channel_new("x11", | 1584 | c = channel_new(ssh, "x11", |
2009 | SSH_CHANNEL_X11_OPEN, sock, sock, -1, | 1585 | SSH_CHANNEL_X11_OPEN, sock, sock, -1, |
2010 | CHAN_TCP_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, 0, "x11", 1); | 1586 | CHAN_TCP_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, 0, "x11", 1); |
2011 | c->force_drain = 1; | 1587 | c->force_drain = 1; |
@@ -2013,7 +1589,7 @@ client_request_x11(const char *request_type, int rchan) | |||
2013 | } | 1589 | } |
2014 | 1590 | ||
2015 | static Channel * | 1591 | static Channel * |
2016 | client_request_agent(const char *request_type, int rchan) | 1592 | client_request_agent(struct ssh *ssh, const char *request_type, int rchan) |
2017 | { | 1593 | { |
2018 | Channel *c = NULL; | 1594 | Channel *c = NULL; |
2019 | int r, sock; | 1595 | int r, sock; |
@@ -2030,7 +1606,7 @@ client_request_agent(const char *request_type, int rchan) | |||
2030 | __func__, ssh_err(r)); | 1606 | __func__, ssh_err(r)); |
2031 | return NULL; | 1607 | return NULL; |
2032 | } | 1608 | } |
2033 | c = channel_new("authentication agent connection", | 1609 | c = channel_new(ssh, "authentication agent connection", |
2034 | SSH_CHANNEL_OPEN, sock, sock, -1, | 1610 | SSH_CHANNEL_OPEN, sock, sock, -1, |
2035 | CHAN_X11_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, | 1611 | CHAN_X11_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, |
2036 | "authentication agent connection", 1); | 1612 | "authentication agent connection", 1); |
@@ -2039,7 +1615,8 @@ client_request_agent(const char *request_type, int rchan) | |||
2039 | } | 1615 | } |
2040 | 1616 | ||
2041 | int | 1617 | int |
2042 | client_request_tun_fwd(int tun_mode, int local_tun, int remote_tun) | 1618 | client_request_tun_fwd(struct ssh *ssh, int tun_mode, |
1619 | int local_tun, int remote_tun) | ||
2043 | { | 1620 | { |
2044 | Channel *c; | 1621 | Channel *c; |
2045 | int fd; | 1622 | int fd; |
@@ -2047,11 +1624,6 @@ client_request_tun_fwd(int tun_mode, int local_tun, int remote_tun) | |||
2047 | if (tun_mode == SSH_TUNMODE_NO) | 1624 | if (tun_mode == SSH_TUNMODE_NO) |
2048 | return 0; | 1625 | return 0; |
2049 | 1626 | ||
2050 | if (!compat20) { | ||
2051 | error("Tunnel forwarding is not supported for protocol 1"); | ||
2052 | return -1; | ||
2053 | } | ||
2054 | |||
2055 | debug("Requesting tun unit %d in mode %d", local_tun, tun_mode); | 1627 | debug("Requesting tun unit %d in mode %d", local_tun, tun_mode); |
2056 | 1628 | ||
2057 | /* Open local tunnel device */ | 1629 | /* Open local tunnel device */ |
@@ -2060,13 +1632,13 @@ client_request_tun_fwd(int tun_mode, int local_tun, int remote_tun) | |||
2060 | return -1; | 1632 | return -1; |
2061 | } | 1633 | } |
2062 | 1634 | ||
2063 | c = channel_new("tun", SSH_CHANNEL_OPENING, fd, fd, -1, | 1635 | c = channel_new(ssh, "tun", SSH_CHANNEL_OPENING, fd, fd, -1, |
2064 | CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, "tun", 1); | 1636 | CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, "tun", 1); |
2065 | c->datagram = 1; | 1637 | c->datagram = 1; |
2066 | 1638 | ||
2067 | #if defined(SSH_TUN_FILTER) | 1639 | #if defined(SSH_TUN_FILTER) |
2068 | if (options.tun_open == SSH_TUNMODE_POINTOPOINT) | 1640 | if (options.tun_open == SSH_TUNMODE_POINTOPOINT) |
2069 | channel_register_filter(c->self, sys_tun_infilter, | 1641 | channel_register_filter(ssh, c->self, sys_tun_infilter, |
2070 | sys_tun_outfilter, NULL, NULL); | 1642 | sys_tun_outfilter, NULL, NULL); |
2071 | #endif | 1643 | #endif |
2072 | 1644 | ||
@@ -2084,7 +1656,7 @@ client_request_tun_fwd(int tun_mode, int local_tun, int remote_tun) | |||
2084 | 1656 | ||
2085 | /* XXXX move to generic input handler */ | 1657 | /* XXXX move to generic input handler */ |
2086 | static int | 1658 | static int |
2087 | client_input_channel_open(int type, u_int32_t seq, void *ctxt) | 1659 | client_input_channel_open(int type, u_int32_t seq, struct ssh *ssh) |
2088 | { | 1660 | { |
2089 | Channel *c = NULL; | 1661 | Channel *c = NULL; |
2090 | char *ctype; | 1662 | char *ctype; |
@@ -2100,20 +1672,21 @@ client_input_channel_open(int type, u_int32_t seq, void *ctxt) | |||
2100 | ctype, rchan, rwindow, rmaxpack); | 1672 | ctype, rchan, rwindow, rmaxpack); |
2101 | 1673 | ||
2102 | if (strcmp(ctype, "forwarded-tcpip") == 0) { | 1674 | if (strcmp(ctype, "forwarded-tcpip") == 0) { |
2103 | c = client_request_forwarded_tcpip(ctype, rchan, rwindow, | 1675 | c = client_request_forwarded_tcpip(ssh, ctype, rchan, rwindow, |
2104 | rmaxpack); | 1676 | rmaxpack); |
2105 | } else if (strcmp(ctype, "forwarded-streamlocal@openssh.com") == 0) { | 1677 | } else if (strcmp(ctype, "forwarded-streamlocal@openssh.com") == 0) { |
2106 | c = client_request_forwarded_streamlocal(ctype, rchan); | 1678 | c = client_request_forwarded_streamlocal(ssh, ctype, rchan); |
2107 | } else if (strcmp(ctype, "x11") == 0) { | 1679 | } else if (strcmp(ctype, "x11") == 0) { |
2108 | c = client_request_x11(ctype, rchan); | 1680 | c = client_request_x11(ssh, ctype, rchan); |
2109 | } else if (strcmp(ctype, "auth-agent@openssh.com") == 0) { | 1681 | } else if (strcmp(ctype, "auth-agent@openssh.com") == 0) { |
2110 | c = client_request_agent(ctype, rchan); | 1682 | c = client_request_agent(ssh, ctype, rchan); |
2111 | } | 1683 | } |
2112 | if (c != NULL && c->type == SSH_CHANNEL_MUX_CLIENT) { | 1684 | if (c != NULL && c->type == SSH_CHANNEL_MUX_CLIENT) { |
2113 | debug3("proxied to downstream: %s", ctype); | 1685 | debug3("proxied to downstream: %s", ctype); |
2114 | } else if (c != NULL) { | 1686 | } else if (c != NULL) { |
2115 | debug("confirm %s", ctype); | 1687 | debug("confirm %s", ctype); |
2116 | c->remote_id = rchan; | 1688 | c->remote_id = rchan; |
1689 | c->have_remote_id = 1; | ||
2117 | c->remote_window = rwindow; | 1690 | c->remote_window = rwindow; |
2118 | c->remote_maxpacket = rmaxpack; | 1691 | c->remote_maxpacket = rmaxpack; |
2119 | if (c->type != SSH_CHANNEL_CONNECTING) { | 1692 | if (c->type != SSH_CHANNEL_CONNECTING) { |
@@ -2140,15 +1713,15 @@ client_input_channel_open(int type, u_int32_t seq, void *ctxt) | |||
2140 | } | 1713 | } |
2141 | 1714 | ||
2142 | static int | 1715 | static int |
2143 | client_input_channel_req(int type, u_int32_t seq, void *ctxt) | 1716 | client_input_channel_req(int type, u_int32_t seq, struct ssh *ssh) |
2144 | { | 1717 | { |
2145 | Channel *c = NULL; | 1718 | Channel *c = NULL; |
2146 | int exitval, id, reply, success = 0; | 1719 | int exitval, id, reply, success = 0; |
2147 | char *rtype; | 1720 | char *rtype; |
2148 | 1721 | ||
2149 | id = packet_get_int(); | 1722 | id = packet_get_int(); |
2150 | c = channel_lookup(id); | 1723 | c = channel_lookup(ssh, id); |
2151 | if (channel_proxy_upstream(c, type, seq, ctxt)) | 1724 | if (channel_proxy_upstream(c, type, seq, ssh)) |
2152 | return 0; | 1725 | return 0; |
2153 | rtype = packet_get_string(NULL); | 1726 | rtype = packet_get_string(NULL); |
2154 | reply = packet_get_char(); | 1727 | reply = packet_get_char(); |
@@ -2163,11 +1736,11 @@ client_input_channel_req(int type, u_int32_t seq, void *ctxt) | |||
2163 | "unknown channel", id); | 1736 | "unknown channel", id); |
2164 | } else if (strcmp(rtype, "eow@openssh.com") == 0) { | 1737 | } else if (strcmp(rtype, "eow@openssh.com") == 0) { |
2165 | packet_check_eom(); | 1738 | packet_check_eom(); |
2166 | chan_rcvd_eow(c); | 1739 | chan_rcvd_eow(ssh, c); |
2167 | } else if (strcmp(rtype, "exit-status") == 0) { | 1740 | } else if (strcmp(rtype, "exit-status") == 0) { |
2168 | exitval = packet_get_int(); | 1741 | exitval = packet_get_int(); |
2169 | if (c->ctl_chan != -1) { | 1742 | if (c->ctl_chan != -1) { |
2170 | mux_exit_message(c, exitval); | 1743 | mux_exit_message(ssh, c, exitval); |
2171 | success = 1; | 1744 | success = 1; |
2172 | } else if (id == session_ident) { | 1745 | } else if (id == session_ident) { |
2173 | /* Record exit value of local session */ | 1746 | /* Record exit value of local session */ |
@@ -2181,6 +1754,9 @@ client_input_channel_req(int type, u_int32_t seq, void *ctxt) | |||
2181 | packet_check_eom(); | 1754 | packet_check_eom(); |
2182 | } | 1755 | } |
2183 | if (reply && c != NULL && !(c->flags & CHAN_CLOSE_SENT)) { | 1756 | if (reply && c != NULL && !(c->flags & CHAN_CLOSE_SENT)) { |
1757 | if (!c->have_remote_id) | ||
1758 | fatal("%s: channel %d: no remote_id", | ||
1759 | __func__, c->self); | ||
2184 | packet_start(success ? | 1760 | packet_start(success ? |
2185 | SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE); | 1761 | SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE); |
2186 | packet_put_int(c->remote_id); | 1762 | packet_put_int(c->remote_id); |
@@ -2202,9 +1778,7 @@ struct hostkeys_update_ctx { | |||
2202 | */ | 1778 | */ |
2203 | struct sshkey **keys; | 1779 | struct sshkey **keys; |
2204 | int *keys_seen; | 1780 | int *keys_seen; |
2205 | size_t nkeys; | 1781 | size_t nkeys, nnew; |
2206 | |||
2207 | size_t nnew; | ||
2208 | 1782 | ||
2209 | /* | 1783 | /* |
2210 | * Keys that are in known_hosts, but were not present in the update | 1784 | * Keys that are in known_hosts, but were not present in the update |
@@ -2241,8 +1815,7 @@ hostkeys_find(struct hostkey_foreach_line *l, void *_ctx) | |||
2241 | size_t i; | 1815 | size_t i; |
2242 | struct sshkey **tmp; | 1816 | struct sshkey **tmp; |
2243 | 1817 | ||
2244 | if (l->status != HKF_STATUS_MATCHED || l->key == NULL || | 1818 | if (l->status != HKF_STATUS_MATCHED || l->key == NULL) |
2245 | l->key->type == KEY_RSA1) | ||
2246 | return 0; | 1819 | return 0; |
2247 | 1820 | ||
2248 | /* Mark off keys we've already seen for this host */ | 1821 | /* Mark off keys we've already seen for this host */ |
@@ -2257,9 +1830,9 @@ hostkeys_find(struct hostkey_foreach_line *l, void *_ctx) | |||
2257 | /* This line contained a key that not offered by the server */ | 1830 | /* This line contained a key that not offered by the server */ |
2258 | debug3("%s: deprecated %s key at %s:%ld", __func__, | 1831 | debug3("%s: deprecated %s key at %s:%ld", __func__, |
2259 | sshkey_ssh_name(l->key), l->path, l->linenum); | 1832 | sshkey_ssh_name(l->key), l->path, l->linenum); |
2260 | if ((tmp = reallocarray(ctx->old_keys, ctx->nold + 1, | 1833 | if ((tmp = recallocarray(ctx->old_keys, ctx->nold, ctx->nold + 1, |
2261 | sizeof(*ctx->old_keys))) == NULL) | 1834 | sizeof(*ctx->old_keys))) == NULL) |
2262 | fatal("%s: reallocarray failed nold = %zu", | 1835 | fatal("%s: recallocarray failed nold = %zu", |
2263 | __func__, ctx->nold); | 1836 | __func__, ctx->nold); |
2264 | ctx->old_keys = tmp; | 1837 | ctx->old_keys = tmp; |
2265 | ctx->old_keys[ctx->nold++] = l->key; | 1838 | ctx->old_keys[ctx->nold++] = l->key; |
@@ -2338,9 +1911,9 @@ update_known_hosts(struct hostkeys_update_ctx *ctx) | |||
2338 | } | 1911 | } |
2339 | 1912 | ||
2340 | static void | 1913 | static void |
2341 | client_global_hostkeys_private_confirm(int type, u_int32_t seq, void *_ctx) | 1914 | client_global_hostkeys_private_confirm(struct ssh *ssh, int type, |
1915 | u_int32_t seq, void *_ctx) | ||
2342 | { | 1916 | { |
2343 | struct ssh *ssh = active_state; /* XXX */ | ||
2344 | struct hostkeys_update_ctx *ctx = (struct hostkeys_update_ctx *)_ctx; | 1917 | struct hostkeys_update_ctx *ctx = (struct hostkeys_update_ctx *)_ctx; |
2345 | size_t i, ndone; | 1918 | size_t i, ndone; |
2346 | struct sshbuf *signdata; | 1919 | struct sshbuf *signdata; |
@@ -2491,9 +2064,9 @@ client_input_hostkeys(void) | |||
2491 | } | 2064 | } |
2492 | } | 2065 | } |
2493 | /* Key is good, record it */ | 2066 | /* Key is good, record it */ |
2494 | if ((tmp = reallocarray(ctx->keys, ctx->nkeys + 1, | 2067 | if ((tmp = recallocarray(ctx->keys, ctx->nkeys, ctx->nkeys + 1, |
2495 | sizeof(*ctx->keys))) == NULL) | 2068 | sizeof(*ctx->keys))) == NULL) |
2496 | fatal("%s: reallocarray failed nkeys = %zu", | 2069 | fatal("%s: recallocarray failed nkeys = %zu", |
2497 | __func__, ctx->nkeys); | 2070 | __func__, ctx->nkeys); |
2498 | ctx->keys = tmp; | 2071 | ctx->keys = tmp; |
2499 | ctx->keys[ctx->nkeys++] = key; | 2072 | ctx->keys[ctx->nkeys++] = key; |
@@ -2581,7 +2154,7 @@ client_input_hostkeys(void) | |||
2581 | } | 2154 | } |
2582 | 2155 | ||
2583 | static int | 2156 | static int |
2584 | client_input_global_request(int type, u_int32_t seq, void *ctxt) | 2157 | client_input_global_request(int type, u_int32_t seq, struct ssh *ssh) |
2585 | { | 2158 | { |
2586 | char *rtype; | 2159 | char *rtype; |
2587 | int want_reply; | 2160 | int want_reply; |
@@ -2604,7 +2177,7 @@ client_input_global_request(int type, u_int32_t seq, void *ctxt) | |||
2604 | } | 2177 | } |
2605 | 2178 | ||
2606 | void | 2179 | void |
2607 | client_session2_setup(int id, int want_tty, int want_subsystem, | 2180 | client_session2_setup(struct ssh *ssh, int id, int want_tty, int want_subsystem, |
2608 | const char *term, struct termios *tiop, int in_fd, Buffer *cmd, char **env) | 2181 | const char *term, struct termios *tiop, int in_fd, Buffer *cmd, char **env) |
2609 | { | 2182 | { |
2610 | int len; | 2183 | int len; |
@@ -2612,8 +2185,8 @@ client_session2_setup(int id, int want_tty, int want_subsystem, | |||
2612 | 2185 | ||
2613 | debug2("%s: id %d", __func__, id); | 2186 | debug2("%s: id %d", __func__, id); |
2614 | 2187 | ||
2615 | if ((c = channel_lookup(id)) == NULL) | 2188 | if ((c = channel_lookup(ssh, id)) == NULL) |
2616 | fatal("client_session2_setup: channel %d: unknown channel", id); | 2189 | fatal("%s: channel %d: unknown channel", __func__, id); |
2617 | 2190 | ||
2618 | packet_set_interactive(want_tty, | 2191 | packet_set_interactive(want_tty, |
2619 | options.ip_qos_interactive, options.ip_qos_bulk); | 2192 | options.ip_qos_interactive, options.ip_qos_bulk); |
@@ -2625,8 +2198,8 @@ client_session2_setup(int id, int want_tty, int want_subsystem, | |||
2625 | if (ioctl(in_fd, TIOCGWINSZ, &ws) < 0) | 2198 | if (ioctl(in_fd, TIOCGWINSZ, &ws) < 0) |
2626 | memset(&ws, 0, sizeof(ws)); | 2199 | memset(&ws, 0, sizeof(ws)); |
2627 | 2200 | ||
2628 | channel_request_start(id, "pty-req", 1); | 2201 | channel_request_start(ssh, id, "pty-req", 1); |
2629 | client_expect_confirm(id, "PTY allocation", CONFIRM_TTY); | 2202 | client_expect_confirm(ssh, id, "PTY allocation", CONFIRM_TTY); |
2630 | packet_put_cstring(term != NULL ? term : ""); | 2203 | packet_put_cstring(term != NULL ? term : ""); |
2631 | packet_put_int((u_int)ws.ws_col); | 2204 | packet_put_int((u_int)ws.ws_col); |
2632 | packet_put_int((u_int)ws.ws_row); | 2205 | packet_put_int((u_int)ws.ws_row); |
@@ -2669,7 +2242,7 @@ client_session2_setup(int id, int want_tty, int want_subsystem, | |||
2669 | } | 2242 | } |
2670 | 2243 | ||
2671 | debug("Sending env %s = %s", name, val); | 2244 | debug("Sending env %s = %s", name, val); |
2672 | channel_request_start(id, "env", 0); | 2245 | channel_request_start(ssh, id, "env", 0); |
2673 | packet_put_cstring(name); | 2246 | packet_put_cstring(name); |
2674 | packet_put_cstring(val); | 2247 | packet_put_cstring(val); |
2675 | packet_send(); | 2248 | packet_send(); |
@@ -2684,25 +2257,26 @@ client_session2_setup(int id, int want_tty, int want_subsystem, | |||
2684 | if (want_subsystem) { | 2257 | if (want_subsystem) { |
2685 | debug("Sending subsystem: %.*s", | 2258 | debug("Sending subsystem: %.*s", |
2686 | len, (u_char*)buffer_ptr(cmd)); | 2259 | len, (u_char*)buffer_ptr(cmd)); |
2687 | channel_request_start(id, "subsystem", 1); | 2260 | channel_request_start(ssh, id, "subsystem", 1); |
2688 | client_expect_confirm(id, "subsystem", CONFIRM_CLOSE); | 2261 | client_expect_confirm(ssh, id, "subsystem", |
2262 | CONFIRM_CLOSE); | ||
2689 | } else { | 2263 | } else { |
2690 | debug("Sending command: %.*s", | 2264 | debug("Sending command: %.*s", |
2691 | len, (u_char*)buffer_ptr(cmd)); | 2265 | len, (u_char*)buffer_ptr(cmd)); |
2692 | channel_request_start(id, "exec", 1); | 2266 | channel_request_start(ssh, id, "exec", 1); |
2693 | client_expect_confirm(id, "exec", CONFIRM_CLOSE); | 2267 | client_expect_confirm(ssh, id, "exec", CONFIRM_CLOSE); |
2694 | } | 2268 | } |
2695 | packet_put_string(buffer_ptr(cmd), buffer_len(cmd)); | 2269 | packet_put_string(buffer_ptr(cmd), buffer_len(cmd)); |
2696 | packet_send(); | 2270 | packet_send(); |
2697 | } else { | 2271 | } else { |
2698 | channel_request_start(id, "shell", 1); | 2272 | channel_request_start(ssh, id, "shell", 1); |
2699 | client_expect_confirm(id, "shell", CONFIRM_CLOSE); | 2273 | client_expect_confirm(ssh, id, "shell", CONFIRM_CLOSE); |
2700 | packet_send(); | 2274 | packet_send(); |
2701 | } | 2275 | } |
2702 | } | 2276 | } |
2703 | 2277 | ||
2704 | static void | 2278 | static void |
2705 | client_init_dispatch_20(void) | 2279 | client_init_dispatch(void) |
2706 | { | 2280 | { |
2707 | dispatch_init(&dispatch_protocol_error); | 2281 | dispatch_init(&dispatch_protocol_error); |
2708 | 2282 | ||
@@ -2727,45 +2301,6 @@ client_init_dispatch_20(void) | |||
2727 | dispatch_set(SSH2_MSG_REQUEST_SUCCESS, &client_global_request_reply); | 2301 | dispatch_set(SSH2_MSG_REQUEST_SUCCESS, &client_global_request_reply); |
2728 | } | 2302 | } |
2729 | 2303 | ||
2730 | static void | ||
2731 | client_init_dispatch_13(void) | ||
2732 | { | ||
2733 | dispatch_init(NULL); | ||
2734 | dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_close); | ||
2735 | dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, &channel_input_close_confirmation); | ||
2736 | dispatch_set(SSH_MSG_CHANNEL_DATA, &channel_input_data); | ||
2737 | dispatch_set(SSH_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation); | ||
2738 | dispatch_set(SSH_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure); | ||
2739 | dispatch_set(SSH_MSG_PORT_OPEN, &channel_input_port_open); | ||
2740 | dispatch_set(SSH_SMSG_EXITSTATUS, &client_input_exit_status); | ||
2741 | dispatch_set(SSH_SMSG_STDERR_DATA, &client_input_stderr_data); | ||
2742 | dispatch_set(SSH_SMSG_STDOUT_DATA, &client_input_stdout_data); | ||
2743 | |||
2744 | dispatch_set(SSH_SMSG_AGENT_OPEN, options.forward_agent ? | ||
2745 | &client_input_agent_open : &deny_input_open); | ||
2746 | dispatch_set(SSH_SMSG_X11_OPEN, options.forward_x11 ? | ||
2747 | &x11_input_open : &deny_input_open); | ||
2748 | } | ||
2749 | |||
2750 | static void | ||
2751 | client_init_dispatch_15(void) | ||
2752 | { | ||
2753 | client_init_dispatch_13(); | ||
2754 | dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_ieof); | ||
2755 | dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, & channel_input_oclose); | ||
2756 | } | ||
2757 | |||
2758 | static void | ||
2759 | client_init_dispatch(void) | ||
2760 | { | ||
2761 | if (compat20) | ||
2762 | client_init_dispatch_20(); | ||
2763 | else if (compat13) | ||
2764 | client_init_dispatch_13(); | ||
2765 | else | ||
2766 | client_init_dispatch_15(); | ||
2767 | } | ||
2768 | |||
2769 | void | 2304 | void |
2770 | client_stop_mux(void) | 2305 | client_stop_mux(void) |
2771 | { | 2306 | { |