diff options
Diffstat (limited to 'clientloop.c')
-rw-r--r-- | clientloop.c | 755 |
1 files changed, 346 insertions, 409 deletions
diff --git a/clientloop.c b/clientloop.c index b57fda042..f10fab769 100644 --- a/clientloop.c +++ b/clientloop.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: clientloop.c,v 1.181 2007/08/15 08:14:46 markus Exp $ */ | 1 | /* $OpenBSD: clientloop.c,v 1.201 2008/07/16 11:51:14 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 |
@@ -86,6 +86,7 @@ | |||
86 | #include <pwd.h> | 86 | #include <pwd.h> |
87 | #include <unistd.h> | 87 | #include <unistd.h> |
88 | 88 | ||
89 | #include "openbsd-compat/sys-queue.h" | ||
89 | #include "xmalloc.h" | 90 | #include "xmalloc.h" |
90 | #include "ssh.h" | 91 | #include "ssh.h" |
91 | #include "ssh1.h" | 92 | #include "ssh1.h" |
@@ -120,7 +121,7 @@ extern int stdin_null_flag; | |||
120 | extern int no_shell_flag; | 121 | extern int no_shell_flag; |
121 | 122 | ||
122 | /* Control socket */ | 123 | /* Control socket */ |
123 | extern int control_fd; | 124 | extern int muxserver_sock; |
124 | 125 | ||
125 | /* | 126 | /* |
126 | * Name of the host we are connecting to. This is the name given on the | 127 | * Name of the host we are connecting to. This is the name given on the |
@@ -143,36 +144,46 @@ static int in_non_blocking_mode = 0; | |||
143 | 144 | ||
144 | /* Common data for the client loop code. */ | 145 | /* Common data for the client loop code. */ |
145 | static volatile sig_atomic_t quit_pending; /* Set non-zero to quit the loop. */ | 146 | static volatile sig_atomic_t quit_pending; /* Set non-zero to quit the loop. */ |
146 | static int escape_char; /* Escape character. */ | 147 | static int escape_char1; /* Escape character. (proto1 only) */ |
147 | static int escape_pending; /* Last character was the escape character */ | 148 | static int escape_pending1; /* Last character was an escape (proto1 only) */ |
148 | static int last_was_cr; /* Last character was a newline. */ | 149 | static int last_was_cr; /* Last character was a newline. */ |
149 | static int exit_status; /* Used to store the exit status of the command. */ | 150 | static int exit_status; /* Used to store the command exit status. */ |
150 | static int stdin_eof; /* EOF has been encountered on standard error. */ | 151 | static int stdin_eof; /* EOF has been encountered on stderr. */ |
151 | static Buffer stdin_buffer; /* Buffer for stdin data. */ | 152 | static Buffer stdin_buffer; /* Buffer for stdin data. */ |
152 | static Buffer stdout_buffer; /* Buffer for stdout data. */ | 153 | static Buffer stdout_buffer; /* Buffer for stdout data. */ |
153 | static Buffer stderr_buffer; /* Buffer for stderr data. */ | 154 | static Buffer stderr_buffer; /* Buffer for stderr data. */ |
154 | static u_long stdin_bytes, stdout_bytes, stderr_bytes; | ||
155 | static u_int buffer_high;/* Soft max buffer size. */ | 155 | static u_int buffer_high;/* Soft max buffer size. */ |
156 | static int connection_in; /* Connection to server (input). */ | 156 | static int connection_in; /* Connection to server (input). */ |
157 | static int connection_out; /* Connection to server (output). */ | 157 | static int connection_out; /* Connection to server (output). */ |
158 | static int need_rekeying; /* Set to non-zero if rekeying is requested. */ | 158 | static int need_rekeying; /* Set to non-zero if rekeying is requested. */ |
159 | static int session_closed = 0; /* In SSH2: login session closed. */ | 159 | static int session_closed = 0; /* In SSH2: login session closed. */ |
160 | static int server_alive_timeouts = 0; | ||
161 | 160 | ||
162 | static void client_init_dispatch(void); | 161 | static void client_init_dispatch(void); |
163 | int session_ident = -1; | 162 | int session_ident = -1; |
164 | 163 | ||
165 | struct confirm_ctx { | 164 | /* Track escape per proto2 channel */ |
166 | int want_tty; | 165 | struct escape_filter_ctx { |
167 | int want_subsys; | 166 | int escape_pending; |
168 | int want_x_fwd; | 167 | int escape_char; |
169 | int want_agent_fwd; | ||
170 | Buffer cmd; | ||
171 | char *term; | ||
172 | struct termios tio; | ||
173 | char **env; | ||
174 | }; | 168 | }; |
175 | 169 | ||
170 | /* Context for channel confirmation replies */ | ||
171 | struct channel_reply_ctx { | ||
172 | const char *request_type; | ||
173 | int id, do_close; | ||
174 | }; | ||
175 | |||
176 | /* Global request success/failure callbacks */ | ||
177 | struct global_confirm { | ||
178 | TAILQ_ENTRY(global_confirm) entry; | ||
179 | global_confirm_cb *cb; | ||
180 | void *ctx; | ||
181 | int ref_count; | ||
182 | }; | ||
183 | TAILQ_HEAD(global_confirms, global_confirm); | ||
184 | static struct global_confirms global_confirms = | ||
185 | TAILQ_HEAD_INITIALIZER(global_confirms); | ||
186 | |||
176 | /*XXX*/ | 187 | /*XXX*/ |
177 | extern Kex *xxx_kex; | 188 | extern Kex *xxx_kex; |
178 | 189 | ||
@@ -380,7 +391,10 @@ client_check_initial_eof_on_stdin(void) | |||
380 | /* Check for immediate EOF on stdin. */ | 391 | /* Check for immediate EOF on stdin. */ |
381 | len = read(fileno(stdin), buf, 1); | 392 | len = read(fileno(stdin), buf, 1); |
382 | if (len == 0) { | 393 | if (len == 0) { |
383 | /* EOF. Record that we have seen it and send EOF to server. */ | 394 | /* |
395 | * EOF. Record that we have seen it and send | ||
396 | * EOF to server. | ||
397 | */ | ||
384 | debug("Sending eof."); | 398 | debug("Sending eof."); |
385 | stdin_eof = 1; | 399 | stdin_eof = 1; |
386 | packet_start(SSH_CMSG_EOF); | 400 | packet_start(SSH_CMSG_EOF); |
@@ -391,8 +405,8 @@ client_check_initial_eof_on_stdin(void) | |||
391 | * and also process it as an escape character if | 405 | * and also process it as an escape character if |
392 | * appropriate. | 406 | * appropriate. |
393 | */ | 407 | */ |
394 | if ((u_char) buf[0] == escape_char) | 408 | if ((u_char) buf[0] == escape_char1) |
395 | escape_pending = 1; | 409 | escape_pending1 = 1; |
396 | else | 410 | else |
397 | buffer_append(&stdin_buffer, buf, 1); | 411 | buffer_append(&stdin_buffer, buf, 1); |
398 | } | 412 | } |
@@ -422,7 +436,6 @@ client_make_packets_from_stdin_data(void) | |||
422 | packet_put_string(buffer_ptr(&stdin_buffer), len); | 436 | packet_put_string(buffer_ptr(&stdin_buffer), len); |
423 | packet_send(); | 437 | packet_send(); |
424 | buffer_consume(&stdin_buffer, len); | 438 | buffer_consume(&stdin_buffer, len); |
425 | stdin_bytes += len; | ||
426 | /* If we have a pending EOF, send it now. */ | 439 | /* If we have a pending EOF, send it now. */ |
427 | if (stdin_eof && buffer_len(&stdin_buffer) == 0) { | 440 | if (stdin_eof && buffer_len(&stdin_buffer) == 0) { |
428 | packet_start(SSH_CMSG_EOF); | 441 | packet_start(SSH_CMSG_EOF); |
@@ -467,14 +480,25 @@ client_check_window_change(void) | |||
467 | static void | 480 | static void |
468 | client_global_request_reply(int type, u_int32_t seq, void *ctxt) | 481 | client_global_request_reply(int type, u_int32_t seq, void *ctxt) |
469 | { | 482 | { |
470 | server_alive_timeouts = 0; | 483 | struct global_confirm *gc; |
471 | client_global_request_reply_fwd(type, seq, ctxt); | 484 | |
485 | if ((gc = TAILQ_FIRST(&global_confirms)) == NULL) | ||
486 | return; | ||
487 | if (gc->cb != NULL) | ||
488 | gc->cb(type, seq, gc->ctx); | ||
489 | if (--gc->ref_count <= 0) { | ||
490 | TAILQ_REMOVE(&global_confirms, gc, entry); | ||
491 | bzero(gc, sizeof(*gc)); | ||
492 | xfree(gc); | ||
493 | } | ||
494 | |||
495 | keep_alive_timeouts = 0; | ||
472 | } | 496 | } |
473 | 497 | ||
474 | static void | 498 | static void |
475 | server_alive_check(void) | 499 | server_alive_check(void) |
476 | { | 500 | { |
477 | if (++server_alive_timeouts > options.server_alive_count_max) { | 501 | if (++keep_alive_timeouts > options.server_alive_count_max) { |
478 | logit("Timeout, server not responding."); | 502 | logit("Timeout, server not responding."); |
479 | cleanup_exit(255); | 503 | cleanup_exit(255); |
480 | } | 504 | } |
@@ -482,6 +506,8 @@ server_alive_check(void) | |||
482 | packet_put_cstring("keepalive@openssh.com"); | 506 | packet_put_cstring("keepalive@openssh.com"); |
483 | packet_put_char(1); /* boolean: want reply */ | 507 | packet_put_char(1); /* boolean: want reply */ |
484 | packet_send(); | 508 | packet_send(); |
509 | /* Insert an empty placeholder to maintain ordering */ | ||
510 | client_register_global_confirm(NULL, NULL); | ||
485 | } | 511 | } |
486 | 512 | ||
487 | /* | 513 | /* |
@@ -533,8 +559,8 @@ client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, | |||
533 | if (packet_have_data_to_write()) | 559 | if (packet_have_data_to_write()) |
534 | FD_SET(connection_out, *writesetp); | 560 | FD_SET(connection_out, *writesetp); |
535 | 561 | ||
536 | if (control_fd != -1) | 562 | if (muxserver_sock != -1) |
537 | FD_SET(control_fd, *readsetp); | 563 | FD_SET(muxserver_sock, *readsetp); |
538 | 564 | ||
539 | /* | 565 | /* |
540 | * Wait for something to happen. This will suspend the process until | 566 | * Wait for something to happen. This will suspend the process until |
@@ -576,9 +602,11 @@ client_suspend_self(Buffer *bin, Buffer *bout, Buffer *berr) | |||
576 | { | 602 | { |
577 | /* Flush stdout and stderr buffers. */ | 603 | /* Flush stdout and stderr buffers. */ |
578 | if (buffer_len(bout) > 0) | 604 | if (buffer_len(bout) > 0) |
579 | atomicio(vwrite, fileno(stdout), buffer_ptr(bout), buffer_len(bout)); | 605 | atomicio(vwrite, fileno(stdout), buffer_ptr(bout), |
606 | buffer_len(bout)); | ||
580 | if (buffer_len(berr) > 0) | 607 | if (buffer_len(berr) > 0) |
581 | atomicio(vwrite, fileno(stderr), buffer_ptr(berr), buffer_len(berr)); | 608 | atomicio(vwrite, fileno(stderr), buffer_ptr(berr), |
609 | buffer_len(berr)); | ||
582 | 610 | ||
583 | leave_raw_mode(); | 611 | leave_raw_mode(); |
584 | 612 | ||
@@ -618,9 +646,13 @@ client_process_net_input(fd_set *readset) | |||
618 | /* Read as much as possible. */ | 646 | /* Read as much as possible. */ |
619 | len = read(connection_in, buf, sizeof(buf)); | 647 | len = read(connection_in, buf, sizeof(buf)); |
620 | if (len == 0) { | 648 | if (len == 0) { |
621 | /* Received EOF. The remote host has closed the connection. */ | 649 | /* |
622 | snprintf(buf, sizeof buf, "Connection to %.300s closed by remote host.\r\n", | 650 | * Received EOF. The remote host has closed the |
623 | host); | 651 | * connection. |
652 | */ | ||
653 | snprintf(buf, sizeof buf, | ||
654 | "Connection to %.300s closed by remote host.\r\n", | ||
655 | host); | ||
624 | buffer_append(&stderr_buffer, buf, strlen(buf)); | 656 | buffer_append(&stderr_buffer, buf, strlen(buf)); |
625 | quit_pending = 1; | 657 | quit_pending = 1; |
626 | return; | 658 | return; |
@@ -629,13 +661,18 @@ client_process_net_input(fd_set *readset) | |||
629 | * There is a kernel bug on Solaris that causes select to | 661 | * There is a kernel bug on Solaris that causes select to |
630 | * sometimes wake up even though there is no data available. | 662 | * sometimes wake up even though there is no data available. |
631 | */ | 663 | */ |
632 | if (len < 0 && (errno == EAGAIN || errno == EINTR)) | 664 | if (len < 0 && |
665 | (errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK)) | ||
633 | len = 0; | 666 | len = 0; |
634 | 667 | ||
635 | if (len < 0) { | 668 | if (len < 0) { |
636 | /* An error has encountered. Perhaps there is a network problem. */ | 669 | /* |
637 | snprintf(buf, sizeof buf, "Read from remote host %.300s: %.100s\r\n", | 670 | * An error has encountered. Perhaps there is a |
638 | host, strerror(errno)); | 671 | * network problem. |
672 | */ | ||
673 | snprintf(buf, sizeof buf, | ||
674 | "Read from remote host %.300s: %.100s\r\n", | ||
675 | host, strerror(errno)); | ||
639 | buffer_append(&stderr_buffer, buf, strlen(buf)); | 676 | buffer_append(&stderr_buffer, buf, strlen(buf)); |
640 | quit_pending = 1; | 677 | quit_pending = 1; |
641 | return; | 678 | return; |
@@ -645,289 +682,81 @@ client_process_net_input(fd_set *readset) | |||
645 | } | 682 | } |
646 | 683 | ||
647 | static void | 684 | static void |
648 | client_subsystem_reply(int type, u_int32_t seq, void *ctxt) | 685 | client_status_confirm(int type, Channel *c, void *ctx) |
649 | { | 686 | { |
650 | int id; | 687 | struct channel_reply_ctx *cr = (struct channel_reply_ctx *)ctx; |
651 | Channel *c; | 688 | char errmsg[256]; |
652 | 689 | int tochan; | |
653 | id = packet_get_int(); | 690 | |
654 | packet_check_eom(); | 691 | /* XXX supress on mux _client_ quietmode */ |
655 | 692 | tochan = options.log_level >= SYSLOG_LEVEL_ERROR && | |
656 | if ((c = channel_lookup(id)) == NULL) { | 693 | c->ctl_fd != -1 && c->extended_usage == CHAN_EXTENDED_WRITE; |
657 | error("%s: no channel for id %d", __func__, id); | 694 | |
658 | return; | 695 | if (type == SSH2_MSG_CHANNEL_SUCCESS) { |
659 | } | 696 | debug2("%s request accepted on channel %d", |
660 | 697 | cr->request_type, c->self); | |
661 | if (type == SSH2_MSG_CHANNEL_SUCCESS) | 698 | } else if (type == SSH2_MSG_CHANNEL_FAILURE) { |
662 | debug2("Request suceeded on channel %d", id); | 699 | if (tochan) { |
663 | else if (type == SSH2_MSG_CHANNEL_FAILURE) { | 700 | snprintf(errmsg, sizeof(errmsg), |
664 | error("Request failed on channel %d", id); | 701 | "%s request failed\r\n", cr->request_type); |
665 | channel_free(c); | 702 | } else { |
703 | snprintf(errmsg, sizeof(errmsg), | ||
704 | "%s request failed on channel %d", | ||
705 | cr->request_type, c->self); | ||
706 | } | ||
707 | /* If error occurred on primary session channel, then exit */ | ||
708 | if (cr->do_close && c->self == session_ident) | ||
709 | fatal("%s", errmsg); | ||
710 | /* If error occurred on mux client, append to their stderr */ | ||
711 | if (tochan) | ||
712 | buffer_append(&c->extended, errmsg, strlen(errmsg)); | ||
713 | else | ||
714 | error("%s", errmsg); | ||
715 | if (cr->do_close) { | ||
716 | chan_read_failed(c); | ||
717 | chan_write_failed(c); | ||
718 | } | ||
666 | } | 719 | } |
720 | xfree(cr); | ||
667 | } | 721 | } |
668 | 722 | ||
669 | static void | 723 | static void |
670 | client_extra_session2_setup(int id, void *arg) | 724 | client_abandon_status_confirm(Channel *c, void *ctx) |
671 | { | 725 | { |
672 | struct confirm_ctx *cctx = arg; | 726 | xfree(ctx); |
673 | const char *display; | ||
674 | Channel *c; | ||
675 | int i; | ||
676 | |||
677 | if (cctx == NULL) | ||
678 | fatal("%s: cctx == NULL", __func__); | ||
679 | if ((c = channel_lookup(id)) == NULL) | ||
680 | fatal("%s: no channel for id %d", __func__, id); | ||
681 | |||
682 | display = getenv("DISPLAY"); | ||
683 | if (cctx->want_x_fwd && options.forward_x11 && display != NULL) { | ||
684 | char *proto, *data; | ||
685 | /* Get reasonable local authentication information. */ | ||
686 | client_x11_get_proto(display, options.xauth_location, | ||
687 | options.forward_x11_trusted, &proto, &data); | ||
688 | /* Request forwarding with authentication spoofing. */ | ||
689 | debug("Requesting X11 forwarding with authentication spoofing."); | ||
690 | x11_request_forwarding_with_spoofing(id, display, proto, data); | ||
691 | /* XXX wait for reply */ | ||
692 | } | ||
693 | |||
694 | if (cctx->want_agent_fwd && options.forward_agent) { | ||
695 | debug("Requesting authentication agent forwarding."); | ||
696 | channel_request_start(id, "auth-agent-req@openssh.com", 0); | ||
697 | packet_send(); | ||
698 | } | ||
699 | |||
700 | client_session2_setup(id, cctx->want_tty, cctx->want_subsys, | ||
701 | cctx->term, &cctx->tio, c->rfd, &cctx->cmd, cctx->env, | ||
702 | client_subsystem_reply); | ||
703 | |||
704 | c->confirm_ctx = NULL; | ||
705 | buffer_free(&cctx->cmd); | ||
706 | xfree(cctx->term); | ||
707 | if (cctx->env != NULL) { | ||
708 | for (i = 0; cctx->env[i] != NULL; i++) | ||
709 | xfree(cctx->env[i]); | ||
710 | xfree(cctx->env); | ||
711 | } | ||
712 | xfree(cctx); | ||
713 | } | 727 | } |
714 | 728 | ||
715 | static void | 729 | static void |
716 | client_process_control(fd_set *readset) | 730 | client_expect_confirm(int id, const char *request, int do_close) |
717 | { | 731 | { |
718 | Buffer m; | 732 | struct channel_reply_ctx *cr = xmalloc(sizeof(*cr)); |
719 | Channel *c; | ||
720 | int client_fd, new_fd[3], ver, allowed, window, packetmax; | ||
721 | socklen_t addrlen; | ||
722 | struct sockaddr_storage addr; | ||
723 | struct confirm_ctx *cctx; | ||
724 | char *cmd; | ||
725 | u_int i, len, env_len, command, flags; | ||
726 | uid_t euid; | ||
727 | gid_t egid; | ||
728 | |||
729 | /* | ||
730 | * Accept connection on control socket | ||
731 | */ | ||
732 | if (control_fd == -1 || !FD_ISSET(control_fd, readset)) | ||
733 | return; | ||
734 | |||
735 | memset(&addr, 0, sizeof(addr)); | ||
736 | addrlen = sizeof(addr); | ||
737 | if ((client_fd = accept(control_fd, | ||
738 | (struct sockaddr*)&addr, &addrlen)) == -1) { | ||
739 | error("%s accept: %s", __func__, strerror(errno)); | ||
740 | return; | ||
741 | } | ||
742 | |||
743 | if (getpeereid(client_fd, &euid, &egid) < 0) { | ||
744 | error("%s getpeereid failed: %s", __func__, strerror(errno)); | ||
745 | close(client_fd); | ||
746 | return; | ||
747 | } | ||
748 | if ((euid != 0) && (getuid() != euid)) { | ||
749 | error("control mode uid mismatch: peer euid %u != uid %u", | ||
750 | (u_int) euid, (u_int) getuid()); | ||
751 | close(client_fd); | ||
752 | return; | ||
753 | } | ||
754 | |||
755 | unset_nonblock(client_fd); | ||
756 | |||
757 | /* Read command */ | ||
758 | buffer_init(&m); | ||
759 | if (ssh_msg_recv(client_fd, &m) == -1) { | ||
760 | error("%s: client msg_recv failed", __func__); | ||
761 | close(client_fd); | ||
762 | buffer_free(&m); | ||
763 | return; | ||
764 | } | ||
765 | if ((ver = buffer_get_char(&m)) != SSHMUX_VER) { | ||
766 | error("%s: wrong client version %d", __func__, ver); | ||
767 | buffer_free(&m); | ||
768 | close(client_fd); | ||
769 | return; | ||
770 | } | ||
771 | |||
772 | allowed = 1; | ||
773 | command = buffer_get_int(&m); | ||
774 | flags = buffer_get_int(&m); | ||
775 | |||
776 | buffer_clear(&m); | ||
777 | |||
778 | switch (command) { | ||
779 | case SSHMUX_COMMAND_OPEN: | ||
780 | if (options.control_master == SSHCTL_MASTER_ASK || | ||
781 | options.control_master == SSHCTL_MASTER_AUTO_ASK) | ||
782 | allowed = ask_permission("Allow shared connection " | ||
783 | "to %s? ", host); | ||
784 | /* continue below */ | ||
785 | break; | ||
786 | case SSHMUX_COMMAND_TERMINATE: | ||
787 | if (options.control_master == SSHCTL_MASTER_ASK || | ||
788 | options.control_master == SSHCTL_MASTER_AUTO_ASK) | ||
789 | allowed = ask_permission("Terminate shared connection " | ||
790 | "to %s? ", host); | ||
791 | if (allowed) | ||
792 | quit_pending = 1; | ||
793 | /* FALLTHROUGH */ | ||
794 | case SSHMUX_COMMAND_ALIVE_CHECK: | ||
795 | /* Reply for SSHMUX_COMMAND_TERMINATE and ALIVE_CHECK */ | ||
796 | buffer_clear(&m); | ||
797 | buffer_put_int(&m, allowed); | ||
798 | buffer_put_int(&m, getpid()); | ||
799 | if (ssh_msg_send(client_fd, SSHMUX_VER, &m) == -1) { | ||
800 | error("%s: client msg_send failed", __func__); | ||
801 | close(client_fd); | ||
802 | buffer_free(&m); | ||
803 | return; | ||
804 | } | ||
805 | buffer_free(&m); | ||
806 | close(client_fd); | ||
807 | return; | ||
808 | default: | ||
809 | error("Unsupported command %d", command); | ||
810 | buffer_free(&m); | ||
811 | close(client_fd); | ||
812 | return; | ||
813 | } | ||
814 | |||
815 | /* Reply for SSHMUX_COMMAND_OPEN */ | ||
816 | buffer_clear(&m); | ||
817 | buffer_put_int(&m, allowed); | ||
818 | buffer_put_int(&m, getpid()); | ||
819 | if (ssh_msg_send(client_fd, SSHMUX_VER, &m) == -1) { | ||
820 | error("%s: client msg_send failed", __func__); | ||
821 | close(client_fd); | ||
822 | buffer_free(&m); | ||
823 | return; | ||
824 | } | ||
825 | |||
826 | if (!allowed) { | ||
827 | error("Refused control connection"); | ||
828 | close(client_fd); | ||
829 | buffer_free(&m); | ||
830 | return; | ||
831 | } | ||
832 | 733 | ||
833 | buffer_clear(&m); | 734 | cr->request_type = request; |
834 | if (ssh_msg_recv(client_fd, &m) == -1) { | 735 | cr->do_close = do_close; |
835 | error("%s: client msg_recv failed", __func__); | ||
836 | close(client_fd); | ||
837 | buffer_free(&m); | ||
838 | return; | ||
839 | } | ||
840 | if ((ver = buffer_get_char(&m)) != SSHMUX_VER) { | ||
841 | error("%s: wrong client version %d", __func__, ver); | ||
842 | buffer_free(&m); | ||
843 | close(client_fd); | ||
844 | return; | ||
845 | } | ||
846 | 736 | ||
847 | cctx = xcalloc(1, sizeof(*cctx)); | 737 | channel_register_status_confirm(id, client_status_confirm, |
848 | cctx->want_tty = (flags & SSHMUX_FLAG_TTY) != 0; | 738 | client_abandon_status_confirm, cr); |
849 | cctx->want_subsys = (flags & SSHMUX_FLAG_SUBSYS) != 0; | 739 | } |
850 | cctx->want_x_fwd = (flags & SSHMUX_FLAG_X11_FWD) != 0; | ||
851 | cctx->want_agent_fwd = (flags & SSHMUX_FLAG_AGENT_FWD) != 0; | ||
852 | cctx->term = buffer_get_string(&m, &len); | ||
853 | |||
854 | cmd = buffer_get_string(&m, &len); | ||
855 | buffer_init(&cctx->cmd); | ||
856 | buffer_append(&cctx->cmd, cmd, strlen(cmd)); | ||
857 | |||
858 | env_len = buffer_get_int(&m); | ||
859 | env_len = MIN(env_len, 4096); | ||
860 | debug3("%s: receiving %d env vars", __func__, env_len); | ||
861 | if (env_len != 0) { | ||
862 | cctx->env = xcalloc(env_len + 1, sizeof(*cctx->env)); | ||
863 | for (i = 0; i < env_len; i++) | ||
864 | cctx->env[i] = buffer_get_string(&m, &len); | ||
865 | cctx->env[i] = NULL; | ||
866 | } | ||
867 | 740 | ||
868 | debug2("%s: accepted tty %d, subsys %d, cmd %s", __func__, | 741 | void |
869 | cctx->want_tty, cctx->want_subsys, cmd); | 742 | client_register_global_confirm(global_confirm_cb *cb, void *ctx) |
870 | xfree(cmd); | 743 | { |
871 | 744 | struct global_confirm *gc, *last_gc; | |
872 | /* Gather fds from client */ | 745 | |
873 | new_fd[0] = mm_receive_fd(client_fd); | 746 | /* Coalesce identical callbacks */ |
874 | new_fd[1] = mm_receive_fd(client_fd); | 747 | last_gc = TAILQ_LAST(&global_confirms, global_confirms); |
875 | new_fd[2] = mm_receive_fd(client_fd); | 748 | if (last_gc && last_gc->cb == cb && last_gc->ctx == ctx) { |
876 | 749 | if (++last_gc->ref_count >= INT_MAX) | |
877 | debug2("%s: got fds stdin %d, stdout %d, stderr %d", __func__, | 750 | fatal("%s: last_gc->ref_count = %d", |
878 | new_fd[0], new_fd[1], new_fd[2]); | 751 | __func__, last_gc->ref_count); |
879 | |||
880 | /* Try to pick up ttymodes from client before it goes raw */ | ||
881 | if (cctx->want_tty && tcgetattr(new_fd[0], &cctx->tio) == -1) | ||
882 | error("%s: tcgetattr: %s", __func__, strerror(errno)); | ||
883 | |||
884 | /* This roundtrip is just for synchronisation of ttymodes */ | ||
885 | buffer_clear(&m); | ||
886 | if (ssh_msg_send(client_fd, SSHMUX_VER, &m) == -1) { | ||
887 | error("%s: client msg_send failed", __func__); | ||
888 | close(client_fd); | ||
889 | close(new_fd[0]); | ||
890 | close(new_fd[1]); | ||
891 | close(new_fd[2]); | ||
892 | buffer_free(&m); | ||
893 | xfree(cctx->term); | ||
894 | if (env_len != 0) { | ||
895 | for (i = 0; i < env_len; i++) | ||
896 | xfree(cctx->env[i]); | ||
897 | xfree(cctx->env); | ||
898 | } | ||
899 | return; | 752 | return; |
900 | } | 753 | } |
901 | buffer_free(&m); | ||
902 | |||
903 | /* enable nonblocking unless tty */ | ||
904 | if (!isatty(new_fd[0])) | ||
905 | set_nonblock(new_fd[0]); | ||
906 | if (!isatty(new_fd[1])) | ||
907 | set_nonblock(new_fd[1]); | ||
908 | if (!isatty(new_fd[2])) | ||
909 | set_nonblock(new_fd[2]); | ||
910 | |||
911 | set_nonblock(client_fd); | ||
912 | |||
913 | window = CHAN_SES_WINDOW_DEFAULT; | ||
914 | packetmax = CHAN_SES_PACKET_DEFAULT; | ||
915 | if (cctx->want_tty) { | ||
916 | window >>= 1; | ||
917 | packetmax >>= 1; | ||
918 | } | ||
919 | |||
920 | c = channel_new("session", SSH_CHANNEL_OPENING, | ||
921 | new_fd[0], new_fd[1], new_fd[2], window, packetmax, | ||
922 | CHAN_EXTENDED_WRITE, "client-session", /*nonblock*/0); | ||
923 | 754 | ||
924 | /* XXX */ | 755 | gc = xmalloc(sizeof(*gc)); |
925 | c->ctl_fd = client_fd; | 756 | gc->cb = cb; |
926 | 757 | gc->ctx = ctx; | |
927 | debug3("%s: channel_new: %d", __func__, c->self); | 758 | gc->ref_count = 1; |
928 | 759 | TAILQ_INSERT_TAIL(&global_confirms, gc, entry); | |
929 | channel_send_open(c->self); | ||
930 | channel_register_confirm(c->self, client_extra_session2_setup, cctx); | ||
931 | } | 760 | } |
932 | 761 | ||
933 | static void | 762 | static void |
@@ -940,6 +769,9 @@ process_cmdline(void) | |||
940 | u_short cancel_port; | 769 | u_short cancel_port; |
941 | Forward fwd; | 770 | Forward fwd; |
942 | 771 | ||
772 | bzero(&fwd, sizeof(fwd)); | ||
773 | fwd.listen_host = fwd.connect_host = NULL; | ||
774 | |||
943 | leave_raw_mode(); | 775 | leave_raw_mode(); |
944 | handler = signal(SIGINT, SIG_IGN); | 776 | handler = signal(SIGINT, SIG_IGN); |
945 | cmd = s = read_passphrase("\r\nssh> ", RP_ECHO); | 777 | cmd = s = read_passphrase("\r\nssh> ", RP_ECHO); |
@@ -1039,11 +871,18 @@ out: | |||
1039 | enter_raw_mode(); | 871 | enter_raw_mode(); |
1040 | if (cmd) | 872 | if (cmd) |
1041 | xfree(cmd); | 873 | xfree(cmd); |
874 | if (fwd.listen_host != NULL) | ||
875 | xfree(fwd.listen_host); | ||
876 | if (fwd.connect_host != NULL) | ||
877 | xfree(fwd.connect_host); | ||
1042 | } | 878 | } |
1043 | 879 | ||
1044 | /* process the characters one by one */ | 880 | /* |
881 | * Process the characters one by one, call with c==NULL for proto1 case. | ||
882 | */ | ||
1045 | static int | 883 | static int |
1046 | process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len) | 884 | process_escapes(Channel *c, Buffer *bin, Buffer *bout, Buffer *berr, |
885 | char *buf, int len) | ||
1047 | { | 886 | { |
1048 | char string[1024]; | 887 | char string[1024]; |
1049 | pid_t pid; | 888 | pid_t pid; |
@@ -1051,7 +890,20 @@ process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len) | |||
1051 | u_int i; | 890 | u_int i; |
1052 | u_char ch; | 891 | u_char ch; |
1053 | char *s; | 892 | char *s; |
893 | int *escape_pendingp, escape_char; | ||
894 | struct escape_filter_ctx *efc; | ||
1054 | 895 | ||
896 | if (c == NULL) { | ||
897 | escape_pendingp = &escape_pending1; | ||
898 | escape_char = escape_char1; | ||
899 | } else { | ||
900 | if (c->filter_ctx == NULL) | ||
901 | return 0; | ||
902 | efc = (struct escape_filter_ctx *)c->filter_ctx; | ||
903 | escape_pendingp = &efc->escape_pending; | ||
904 | escape_char = efc->escape_char; | ||
905 | } | ||
906 | |||
1055 | if (len <= 0) | 907 | if (len <= 0) |
1056 | return (0); | 908 | return (0); |
1057 | 909 | ||
@@ -1059,25 +911,42 @@ process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len) | |||
1059 | /* Get one character at a time. */ | 911 | /* Get one character at a time. */ |
1060 | ch = buf[i]; | 912 | ch = buf[i]; |
1061 | 913 | ||
1062 | if (escape_pending) { | 914 | if (*escape_pendingp) { |
1063 | /* We have previously seen an escape character. */ | 915 | /* We have previously seen an escape character. */ |
1064 | /* Clear the flag now. */ | 916 | /* Clear the flag now. */ |
1065 | escape_pending = 0; | 917 | *escape_pendingp = 0; |
1066 | 918 | ||
1067 | /* Process the escaped character. */ | 919 | /* Process the escaped character. */ |
1068 | switch (ch) { | 920 | switch (ch) { |
1069 | case '.': | 921 | case '.': |
1070 | /* Terminate the connection. */ | 922 | /* Terminate the connection. */ |
1071 | snprintf(string, sizeof string, "%c.\r\n", escape_char); | 923 | snprintf(string, sizeof string, "%c.\r\n", |
924 | escape_char); | ||
1072 | buffer_append(berr, string, strlen(string)); | 925 | buffer_append(berr, string, strlen(string)); |
1073 | 926 | ||
1074 | quit_pending = 1; | 927 | if (c && c->ctl_fd != -1) { |
928 | chan_read_failed(c); | ||
929 | chan_write_failed(c); | ||
930 | return 0; | ||
931 | } else | ||
932 | quit_pending = 1; | ||
1075 | return -1; | 933 | return -1; |
1076 | 934 | ||
1077 | case 'Z' - 64: | 935 | case 'Z' - 64: |
1078 | /* Suspend the program. */ | 936 | /* XXX support this for mux clients */ |
1079 | /* Print a message to that effect to the user. */ | 937 | if (c && c->ctl_fd != -1) { |
1080 | snprintf(string, sizeof string, "%c^Z [suspend ssh]\r\n", escape_char); | 938 | noescape: |
939 | snprintf(string, sizeof string, | ||
940 | "%c%c escape not available to " | ||
941 | "multiplexed sessions\r\n", | ||
942 | escape_char, ch); | ||
943 | buffer_append(berr, string, | ||
944 | strlen(string)); | ||
945 | continue; | ||
946 | } | ||
947 | /* Suspend the program. Inform the user */ | ||
948 | snprintf(string, sizeof string, | ||
949 | "%c^Z [suspend ssh]\r\n", escape_char); | ||
1081 | buffer_append(berr, string, strlen(string)); | 950 | buffer_append(berr, string, strlen(string)); |
1082 | 951 | ||
1083 | /* Restore terminal modes and suspend. */ | 952 | /* Restore terminal modes and suspend. */ |
@@ -1102,16 +971,20 @@ process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len) | |||
1102 | case 'R': | 971 | case 'R': |
1103 | if (compat20) { | 972 | if (compat20) { |
1104 | if (datafellows & SSH_BUG_NOREKEY) | 973 | if (datafellows & SSH_BUG_NOREKEY) |
1105 | logit("Server does not support re-keying"); | 974 | logit("Server does not " |
975 | "support re-keying"); | ||
1106 | else | 976 | else |
1107 | need_rekeying = 1; | 977 | need_rekeying = 1; |
1108 | } | 978 | } |
1109 | continue; | 979 | continue; |
1110 | 980 | ||
1111 | case '&': | 981 | case '&': |
982 | if (c && c->ctl_fd != -1) | ||
983 | goto noescape; | ||
1112 | /* | 984 | /* |
1113 | * Detach the program (continue to serve connections, | 985 | * Detach the program (continue to serve |
1114 | * but put in background and no more new connections). | 986 | * connections, but put in background and no |
987 | * more new connections). | ||
1115 | */ | 988 | */ |
1116 | /* Restore tty modes. */ | 989 | /* Restore tty modes. */ |
1117 | leave_raw_mode(); | 990 | leave_raw_mode(); |
@@ -1140,9 +1013,9 @@ process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len) | |||
1140 | return -1; | 1013 | return -1; |
1141 | } else if (!stdin_eof) { | 1014 | } else if (!stdin_eof) { |
1142 | /* | 1015 | /* |
1143 | * Sending SSH_CMSG_EOF alone does not always appear | 1016 | * Sending SSH_CMSG_EOF alone does not |
1144 | * to be enough. So we try to send an EOF character | 1017 | * always appear to be enough. So we |
1145 | * first. | 1018 | * try to send an EOF character first. |
1146 | */ | 1019 | */ |
1147 | packet_start(SSH_CMSG_STDIN_DATA); | 1020 | packet_start(SSH_CMSG_STDIN_DATA); |
1148 | packet_put_string("\004", 1); | 1021 | packet_put_string("\004", 1); |
@@ -1157,27 +1030,50 @@ process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len) | |||
1157 | continue; | 1030 | continue; |
1158 | 1031 | ||
1159 | case '?': | 1032 | case '?': |
1160 | snprintf(string, sizeof string, | 1033 | if (c && c->ctl_fd != -1) { |
1034 | snprintf(string, sizeof string, | ||
1161 | "%c?\r\n\ | 1035 | "%c?\r\n\ |
1162 | Supported escape sequences:\r\n\ | 1036 | Supported escape sequences:\r\n\ |
1163 | %c. - terminate connection\r\n\ | 1037 | %c. - terminate session\r\n\ |
1164 | %cB - send a BREAK to the remote system\r\n\ | 1038 | %cB - send a BREAK to the remote system\r\n\ |
1165 | %cC - open a command line\r\n\ | 1039 | %cC - open a command line\r\n\ |
1166 | %cR - Request rekey (SSH protocol 2 only)\r\n\ | 1040 | %cR - Request rekey (SSH protocol 2 only)\r\n\ |
1167 | %c^Z - suspend ssh\r\n\ | 1041 | %c# - list forwarded connections\r\n\ |
1168 | %c# - list forwarded connections\r\n\ | 1042 | %c? - this message\r\n\ |
1169 | %c& - background ssh (when waiting for connections to terminate)\r\n\ | 1043 | %c%c - send the escape character by typing it twice\r\n\ |
1170 | %c? - this message\r\n\ | ||
1171 | %c%c - send the escape character by typing it twice\r\n\ | ||
1172 | (Note that escapes are only recognized immediately after newline.)\r\n", | 1044 | (Note that escapes are only recognized immediately after newline.)\r\n", |
1173 | escape_char, escape_char, escape_char, escape_char, | 1045 | escape_char, escape_char, |
1174 | escape_char, escape_char, escape_char, escape_char, | 1046 | escape_char, escape_char, |
1175 | escape_char, escape_char, escape_char); | 1047 | escape_char, escape_char, |
1048 | escape_char, escape_char, | ||
1049 | escape_char); | ||
1050 | } else { | ||
1051 | snprintf(string, sizeof string, | ||
1052 | "%c?\r\n\ | ||
1053 | Supported escape sequences:\r\n\ | ||
1054 | %c. - terminate connection (and any multiplexed sessions)\r\n\ | ||
1055 | %cB - send a BREAK to the remote system\r\n\ | ||
1056 | %cC - open a command line\r\n\ | ||
1057 | %cR - Request rekey (SSH protocol 2 only)\r\n\ | ||
1058 | %c^Z - suspend ssh\r\n\ | ||
1059 | %c# - list forwarded connections\r\n\ | ||
1060 | %c& - background ssh (when waiting for connections to terminate)\r\n\ | ||
1061 | %c? - this message\r\n\ | ||
1062 | %c%c - send the escape character by typing it twice\r\n\ | ||
1063 | (Note that escapes are only recognized immediately after newline.)\r\n", | ||
1064 | escape_char, escape_char, | ||
1065 | escape_char, escape_char, | ||
1066 | escape_char, escape_char, | ||
1067 | escape_char, escape_char, | ||
1068 | escape_char, escape_char, | ||
1069 | escape_char); | ||
1070 | } | ||
1176 | buffer_append(berr, string, strlen(string)); | 1071 | buffer_append(berr, string, strlen(string)); |
1177 | continue; | 1072 | continue; |
1178 | 1073 | ||
1179 | case '#': | 1074 | case '#': |
1180 | snprintf(string, sizeof string, "%c#\r\n", escape_char); | 1075 | snprintf(string, sizeof string, "%c#\r\n", |
1076 | escape_char); | ||
1181 | buffer_append(berr, string, strlen(string)); | 1077 | buffer_append(berr, string, strlen(string)); |
1182 | s = channel_open_message(); | 1078 | s = channel_open_message(); |
1183 | buffer_append(berr, s, strlen(s)); | 1079 | buffer_append(berr, s, strlen(s)); |
@@ -1198,12 +1094,15 @@ Supported escape sequences:\r\n\ | |||
1198 | } | 1094 | } |
1199 | } else { | 1095 | } else { |
1200 | /* | 1096 | /* |
1201 | * The previous character was not an escape char. Check if this | 1097 | * The previous character was not an escape char. |
1202 | * is an escape. | 1098 | * Check if this is an escape. |
1203 | */ | 1099 | */ |
1204 | if (last_was_cr && ch == escape_char) { | 1100 | if (last_was_cr && ch == escape_char) { |
1205 | /* It is. Set the flag and continue to next character. */ | 1101 | /* |
1206 | escape_pending = 1; | 1102 | * It is. Set the flag and continue to |
1103 | * next character. | ||
1104 | */ | ||
1105 | *escape_pendingp = 1; | ||
1207 | continue; | 1106 | continue; |
1208 | } | 1107 | } |
1209 | } | 1108 | } |
@@ -1229,7 +1128,8 @@ client_process_input(fd_set *readset) | |||
1229 | if (FD_ISSET(fileno(stdin), readset)) { | 1128 | if (FD_ISSET(fileno(stdin), readset)) { |
1230 | /* Read as much as possible. */ | 1129 | /* Read as much as possible. */ |
1231 | len = read(fileno(stdin), buf, sizeof(buf)); | 1130 | len = read(fileno(stdin), buf, sizeof(buf)); |
1232 | if (len < 0 && (errno == EAGAIN || errno == EINTR)) | 1131 | if (len < 0 && |
1132 | (errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK)) | ||
1233 | return; /* we'll try again later */ | 1133 | return; /* we'll try again later */ |
1234 | if (len <= 0) { | 1134 | if (len <= 0) { |
1235 | /* | 1135 | /* |
@@ -1238,7 +1138,8 @@ client_process_input(fd_set *readset) | |||
1238 | * if it was an error condition. | 1138 | * if it was an error condition. |
1239 | */ | 1139 | */ |
1240 | if (len < 0) { | 1140 | if (len < 0) { |
1241 | snprintf(buf, sizeof buf, "read: %.100s\r\n", strerror(errno)); | 1141 | snprintf(buf, sizeof buf, "read: %.100s\r\n", |
1142 | strerror(errno)); | ||
1242 | buffer_append(&stderr_buffer, buf, strlen(buf)); | 1143 | buffer_append(&stderr_buffer, buf, strlen(buf)); |
1243 | } | 1144 | } |
1244 | /* Mark that we have seen EOF. */ | 1145 | /* Mark that we have seen EOF. */ |
@@ -1254,7 +1155,7 @@ client_process_input(fd_set *readset) | |||
1254 | packet_start(SSH_CMSG_EOF); | 1155 | packet_start(SSH_CMSG_EOF); |
1255 | packet_send(); | 1156 | packet_send(); |
1256 | } | 1157 | } |
1257 | } else if (escape_char == SSH_ESCAPECHAR_NONE) { | 1158 | } else if (escape_char1 == SSH_ESCAPECHAR_NONE) { |
1258 | /* | 1159 | /* |
1259 | * Normal successful read, and no escape character. | 1160 | * Normal successful read, and no escape character. |
1260 | * Just append the data to buffer. | 1161 | * Just append the data to buffer. |
@@ -1262,11 +1163,12 @@ client_process_input(fd_set *readset) | |||
1262 | buffer_append(&stdin_buffer, buf, len); | 1163 | buffer_append(&stdin_buffer, buf, len); |
1263 | } else { | 1164 | } else { |
1264 | /* | 1165 | /* |
1265 | * Normal, successful read. But we have an escape character | 1166 | * Normal, successful read. But we have an escape |
1266 | * and have to process the characters one by one. | 1167 | * character and have to process the characters one |
1168 | * by one. | ||
1267 | */ | 1169 | */ |
1268 | if (process_escapes(&stdin_buffer, &stdout_buffer, | 1170 | if (process_escapes(NULL, &stdin_buffer, |
1269 | &stderr_buffer, buf, len) == -1) | 1171 | &stdout_buffer, &stderr_buffer, buf, len) == -1) |
1270 | return; | 1172 | return; |
1271 | } | 1173 | } |
1272 | } | 1174 | } |
@@ -1284,14 +1186,16 @@ client_process_output(fd_set *writeset) | |||
1284 | len = write(fileno(stdout), buffer_ptr(&stdout_buffer), | 1186 | len = write(fileno(stdout), buffer_ptr(&stdout_buffer), |
1285 | buffer_len(&stdout_buffer)); | 1187 | buffer_len(&stdout_buffer)); |
1286 | if (len <= 0) { | 1188 | if (len <= 0) { |
1287 | if (errno == EINTR || errno == EAGAIN) | 1189 | if (errno == EINTR || errno == EAGAIN || |
1190 | errno == EWOULDBLOCK) | ||
1288 | len = 0; | 1191 | len = 0; |
1289 | else { | 1192 | else { |
1290 | /* | 1193 | /* |
1291 | * An error or EOF was encountered. Put an | 1194 | * An error or EOF was encountered. Put an |
1292 | * error message to stderr buffer. | 1195 | * error message to stderr buffer. |
1293 | */ | 1196 | */ |
1294 | snprintf(buf, sizeof buf, "write stdout: %.50s\r\n", strerror(errno)); | 1197 | snprintf(buf, sizeof buf, |
1198 | "write stdout: %.50s\r\n", strerror(errno)); | ||
1295 | buffer_append(&stderr_buffer, buf, strlen(buf)); | 1199 | buffer_append(&stderr_buffer, buf, strlen(buf)); |
1296 | quit_pending = 1; | 1200 | quit_pending = 1; |
1297 | return; | 1201 | return; |
@@ -1299,7 +1203,6 @@ client_process_output(fd_set *writeset) | |||
1299 | } | 1203 | } |
1300 | /* Consume printed data from the buffer. */ | 1204 | /* Consume printed data from the buffer. */ |
1301 | buffer_consume(&stdout_buffer, len); | 1205 | buffer_consume(&stdout_buffer, len); |
1302 | stdout_bytes += len; | ||
1303 | } | 1206 | } |
1304 | /* Write buffered output to stderr. */ | 1207 | /* Write buffered output to stderr. */ |
1305 | if (FD_ISSET(fileno(stderr), writeset)) { | 1208 | if (FD_ISSET(fileno(stderr), writeset)) { |
@@ -1307,17 +1210,20 @@ client_process_output(fd_set *writeset) | |||
1307 | len = write(fileno(stderr), buffer_ptr(&stderr_buffer), | 1210 | len = write(fileno(stderr), buffer_ptr(&stderr_buffer), |
1308 | buffer_len(&stderr_buffer)); | 1211 | buffer_len(&stderr_buffer)); |
1309 | if (len <= 0) { | 1212 | if (len <= 0) { |
1310 | if (errno == EINTR || errno == EAGAIN) | 1213 | if (errno == EINTR || errno == EAGAIN || |
1214 | errno == EWOULDBLOCK) | ||
1311 | len = 0; | 1215 | len = 0; |
1312 | else { | 1216 | else { |
1313 | /* EOF or error, but can't even print error message. */ | 1217 | /* |
1218 | * EOF or error, but can't even print | ||
1219 | * error message. | ||
1220 | */ | ||
1314 | quit_pending = 1; | 1221 | quit_pending = 1; |
1315 | return; | 1222 | return; |
1316 | } | 1223 | } |
1317 | } | 1224 | } |
1318 | /* Consume printed characters from the buffer. */ | 1225 | /* Consume printed characters from the buffer. */ |
1319 | buffer_consume(&stderr_buffer, len); | 1226 | buffer_consume(&stderr_buffer, len); |
1320 | stderr_bytes += len; | ||
1321 | } | 1227 | } |
1322 | } | 1228 | } |
1323 | 1229 | ||
@@ -1336,16 +1242,39 @@ client_process_output(fd_set *writeset) | |||
1336 | static void | 1242 | static void |
1337 | client_process_buffered_input_packets(void) | 1243 | client_process_buffered_input_packets(void) |
1338 | { | 1244 | { |
1339 | dispatch_run(DISPATCH_NONBLOCK, &quit_pending, compat20 ? xxx_kex : NULL); | 1245 | dispatch_run(DISPATCH_NONBLOCK, &quit_pending, |
1246 | compat20 ? xxx_kex : NULL); | ||
1340 | } | 1247 | } |
1341 | 1248 | ||
1342 | /* scan buf[] for '~' before sending data to the peer */ | 1249 | /* scan buf[] for '~' before sending data to the peer */ |
1343 | 1250 | ||
1344 | static int | 1251 | /* Helper: allocate a new escape_filter_ctx and fill in its escape char */ |
1345 | simple_escape_filter(Channel *c, char *buf, int len) | 1252 | void * |
1253 | client_new_escape_filter_ctx(int escape_char) | ||
1254 | { | ||
1255 | struct escape_filter_ctx *ret; | ||
1256 | |||
1257 | ret = xmalloc(sizeof(*ret)); | ||
1258 | ret->escape_pending = 0; | ||
1259 | ret->escape_char = escape_char; | ||
1260 | return (void *)ret; | ||
1261 | } | ||
1262 | |||
1263 | /* Free the escape filter context on channel free */ | ||
1264 | void | ||
1265 | client_filter_cleanup(int cid, void *ctx) | ||
1266 | { | ||
1267 | xfree(ctx); | ||
1268 | } | ||
1269 | |||
1270 | int | ||
1271 | client_simple_escape_filter(Channel *c, char *buf, int len) | ||
1346 | { | 1272 | { |
1347 | /* XXX we assume c->extended is writeable */ | 1273 | if (c->extended_usage != CHAN_EXTENDED_WRITE) |
1348 | return process_escapes(&c->input, &c->output, &c->extended, buf, len); | 1274 | return 0; |
1275 | |||
1276 | return process_escapes(c, &c->input, &c->output, &c->extended, | ||
1277 | buf, len); | ||
1349 | } | 1278 | } |
1350 | 1279 | ||
1351 | static void | 1280 | static void |
@@ -1369,6 +1298,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1369 | fd_set *readset = NULL, *writeset = NULL; | 1298 | fd_set *readset = NULL, *writeset = NULL; |
1370 | double start_time, total_time; | 1299 | double start_time, total_time; |
1371 | int max_fd = 0, max_fd2 = 0, len, rekeying = 0; | 1300 | int max_fd = 0, max_fd2 = 0, len, rekeying = 0; |
1301 | u_int64_t ibytes, obytes; | ||
1372 | u_int nalloc = 0; | 1302 | u_int nalloc = 0; |
1373 | char buf[100]; | 1303 | char buf[100]; |
1374 | 1304 | ||
@@ -1377,7 +1307,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1377 | start_time = get_current_time(); | 1307 | start_time = get_current_time(); |
1378 | 1308 | ||
1379 | /* Initialize variables. */ | 1309 | /* Initialize variables. */ |
1380 | escape_pending = 0; | 1310 | escape_pending1 = 0; |
1381 | last_was_cr = 1; | 1311 | last_was_cr = 1; |
1382 | exit_status = -1; | 1312 | exit_status = -1; |
1383 | stdin_eof = 0; | 1313 | stdin_eof = 0; |
@@ -1385,8 +1315,8 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1385 | connection_in = packet_get_connection_in(); | 1315 | connection_in = packet_get_connection_in(); |
1386 | connection_out = packet_get_connection_out(); | 1316 | connection_out = packet_get_connection_out(); |
1387 | max_fd = MAX(connection_in, connection_out); | 1317 | max_fd = MAX(connection_in, connection_out); |
1388 | if (control_fd != -1) | 1318 | if (muxserver_sock != -1) |
1389 | max_fd = MAX(max_fd, control_fd); | 1319 | max_fd = MAX(max_fd, muxserver_sock); |
1390 | 1320 | ||
1391 | if (!compat20) { | 1321 | if (!compat20) { |
1392 | /* enable nonblocking unless tty */ | 1322 | /* enable nonblocking unless tty */ |
@@ -1400,11 +1330,8 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1400 | max_fd = MAX(max_fd, fileno(stdout)); | 1330 | max_fd = MAX(max_fd, fileno(stdout)); |
1401 | max_fd = MAX(max_fd, fileno(stderr)); | 1331 | max_fd = MAX(max_fd, fileno(stderr)); |
1402 | } | 1332 | } |
1403 | stdin_bytes = 0; | ||
1404 | stdout_bytes = 0; | ||
1405 | stderr_bytes = 0; | ||
1406 | quit_pending = 0; | 1333 | quit_pending = 0; |
1407 | escape_char = escape_char_arg; | 1334 | escape_char1 = escape_char_arg; |
1408 | 1335 | ||
1409 | /* Initialize buffers. */ | 1336 | /* Initialize buffers. */ |
1410 | buffer_init(&stdin_buffer); | 1337 | buffer_init(&stdin_buffer); |
@@ -1432,9 +1359,11 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1432 | 1359 | ||
1433 | if (compat20) { | 1360 | if (compat20) { |
1434 | session_ident = ssh2_chan_id; | 1361 | session_ident = ssh2_chan_id; |
1435 | if (escape_char != SSH_ESCAPECHAR_NONE) | 1362 | if (escape_char_arg != SSH_ESCAPECHAR_NONE) |
1436 | channel_register_filter(session_ident, | 1363 | channel_register_filter(session_ident, |
1437 | simple_escape_filter, NULL); | 1364 | client_simple_escape_filter, NULL, |
1365 | client_filter_cleanup, | ||
1366 | client_new_escape_filter_ctx(escape_char_arg)); | ||
1438 | if (session_ident != -1) | 1367 | if (session_ident != -1) |
1439 | channel_register_cleanup(session_ident, | 1368 | channel_register_cleanup(session_ident, |
1440 | client_channel_closed, 0); | 1369 | client_channel_closed, 0); |
@@ -1506,7 +1435,10 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1506 | client_process_net_input(readset); | 1435 | client_process_net_input(readset); |
1507 | 1436 | ||
1508 | /* Accept control connections. */ | 1437 | /* Accept control connections. */ |
1509 | client_process_control(readset); | 1438 | if (muxserver_sock != -1 &&FD_ISSET(muxserver_sock, readset)) { |
1439 | if (muxserver_accept_control()) | ||
1440 | quit_pending = 1; | ||
1441 | } | ||
1510 | 1442 | ||
1511 | if (quit_pending) | 1443 | if (quit_pending) |
1512 | break; | 1444 | break; |
@@ -1521,7 +1453,10 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1521 | client_process_output(writeset); | 1453 | client_process_output(writeset); |
1522 | } | 1454 | } |
1523 | 1455 | ||
1524 | /* Send as much buffered packet data as possible to the sender. */ | 1456 | /* |
1457 | * Send as much buffered packet data as possible to the | ||
1458 | * sender. | ||
1459 | */ | ||
1525 | if (FD_ISSET(connection_out, writeset)) | 1460 | if (FD_ISSET(connection_out, writeset)) |
1526 | packet_write_poll(); | 1461 | packet_write_poll(); |
1527 | } | 1462 | } |
@@ -1566,7 +1501,8 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1566 | * that the connection has been closed. | 1501 | * that the connection has been closed. |
1567 | */ | 1502 | */ |
1568 | if (have_pty && options.log_level != SYSLOG_LEVEL_QUIET) { | 1503 | if (have_pty && options.log_level != SYSLOG_LEVEL_QUIET) { |
1569 | snprintf(buf, sizeof buf, "Connection to %.64s closed.\r\n", host); | 1504 | snprintf(buf, sizeof buf, |
1505 | "Connection to %.64s closed.\r\n", host); | ||
1570 | buffer_append(&stderr_buffer, buf, strlen(buf)); | 1506 | buffer_append(&stderr_buffer, buf, strlen(buf)); |
1571 | } | 1507 | } |
1572 | 1508 | ||
@@ -1579,7 +1515,6 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1579 | break; | 1515 | break; |
1580 | } | 1516 | } |
1581 | buffer_consume(&stdout_buffer, len); | 1517 | buffer_consume(&stdout_buffer, len); |
1582 | stdout_bytes += len; | ||
1583 | } | 1518 | } |
1584 | 1519 | ||
1585 | /* Output any buffered data for stderr. */ | 1520 | /* Output any buffered data for stderr. */ |
@@ -1591,7 +1526,6 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1591 | break; | 1526 | break; |
1592 | } | 1527 | } |
1593 | buffer_consume(&stderr_buffer, len); | 1528 | buffer_consume(&stderr_buffer, len); |
1594 | stderr_bytes += len; | ||
1595 | } | 1529 | } |
1596 | 1530 | ||
1597 | /* Clear and free any buffers. */ | 1531 | /* Clear and free any buffers. */ |
@@ -1602,13 +1536,13 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1602 | 1536 | ||
1603 | /* Report bytes transferred, and transfer rates. */ | 1537 | /* Report bytes transferred, and transfer rates. */ |
1604 | total_time = get_current_time() - start_time; | 1538 | total_time = get_current_time() - start_time; |
1605 | debug("Transferred: stdin %lu, stdout %lu, stderr %lu bytes in %.1f seconds", | 1539 | packet_get_state(MODE_IN, NULL, NULL, NULL, &ibytes); |
1606 | stdin_bytes, stdout_bytes, stderr_bytes, total_time); | 1540 | packet_get_state(MODE_OUT, NULL, NULL, NULL, &obytes); |
1541 | verbose("Transferred: sent %llu, received %llu bytes, in %.1f seconds", | ||
1542 | obytes, ibytes, total_time); | ||
1607 | if (total_time > 0) | 1543 | if (total_time > 0) |
1608 | debug("Bytes per second: stdin %.1f, stdout %.1f, stderr %.1f", | 1544 | verbose("Bytes per second: sent %.1f, received %.1f", |
1609 | stdin_bytes / total_time, stdout_bytes / total_time, | 1545 | obytes / total_time, ibytes / total_time); |
1610 | stderr_bytes / total_time); | ||
1611 | |||
1612 | /* Return the exit status of the program. */ | 1546 | /* Return the exit status of the program. */ |
1613 | debug("Exit status %d", exit_status); | 1547 | debug("Exit status %d", exit_status); |
1614 | return exit_status; | 1548 | return exit_status; |
@@ -1699,7 +1633,6 @@ client_request_forwarded_tcpip(const char *request_type, int rchan) | |||
1699 | Channel *c = NULL; | 1633 | Channel *c = NULL; |
1700 | char *listen_address, *originator_address; | 1634 | char *listen_address, *originator_address; |
1701 | int listen_port, originator_port; | 1635 | int listen_port, originator_port; |
1702 | int sock; | ||
1703 | 1636 | ||
1704 | /* Get rest of the packet */ | 1637 | /* Get rest of the packet */ |
1705 | listen_address = packet_get_string(NULL); | 1638 | listen_address = packet_get_string(NULL); |
@@ -1708,19 +1641,13 @@ client_request_forwarded_tcpip(const char *request_type, int rchan) | |||
1708 | originator_port = packet_get_int(); | 1641 | originator_port = packet_get_int(); |
1709 | packet_check_eom(); | 1642 | packet_check_eom(); |
1710 | 1643 | ||
1711 | debug("client_request_forwarded_tcpip: listen %s port %d, originator %s port %d", | 1644 | debug("client_request_forwarded_tcpip: listen %s port %d, " |
1712 | listen_address, listen_port, originator_address, originator_port); | 1645 | "originator %s port %d", listen_address, listen_port, |
1646 | originator_address, originator_port); | ||
1647 | |||
1648 | c = channel_connect_by_listen_address(listen_port, | ||
1649 | "forwarded-tcpip", originator_address); | ||
1713 | 1650 | ||
1714 | sock = channel_connect_by_listen_address(listen_port); | ||
1715 | if (sock < 0) { | ||
1716 | xfree(originator_address); | ||
1717 | xfree(listen_address); | ||
1718 | return NULL; | ||
1719 | } | ||
1720 | c = channel_new("forwarded-tcpip", | ||
1721 | SSH_CHANNEL_CONNECTING, sock, sock, -1, | ||
1722 | CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_WINDOW_DEFAULT, 0, | ||
1723 | originator_address, 1); | ||
1724 | xfree(originator_address); | 1651 | xfree(originator_address); |
1725 | xfree(listen_address); | 1652 | xfree(listen_address); |
1726 | return c; | 1653 | return c; |
@@ -1736,7 +1663,8 @@ client_request_x11(const char *request_type, int rchan) | |||
1736 | 1663 | ||
1737 | if (!options.forward_x11) { | 1664 | if (!options.forward_x11) { |
1738 | error("Warning: ssh server tried X11 forwarding."); | 1665 | error("Warning: ssh server tried X11 forwarding."); |
1739 | error("Warning: this is probably a break-in attempt by a malicious server."); | 1666 | error("Warning: this is probably a break-in attempt by a " |
1667 | "malicious server."); | ||
1740 | return NULL; | 1668 | return NULL; |
1741 | } | 1669 | } |
1742 | originator = packet_get_string(NULL); | 1670 | originator = packet_get_string(NULL); |
@@ -1769,7 +1697,8 @@ client_request_agent(const char *request_type, int rchan) | |||
1769 | 1697 | ||
1770 | if (!options.forward_agent) { | 1698 | if (!options.forward_agent) { |
1771 | error("Warning: ssh server tried agent forwarding."); | 1699 | error("Warning: ssh server tried agent forwarding."); |
1772 | error("Warning: this is probably a break-in attempt by a malicious server."); | 1700 | error("Warning: this is probably a break-in attempt by a " |
1701 | "malicious server."); | ||
1773 | return NULL; | 1702 | return NULL; |
1774 | } | 1703 | } |
1775 | sock = ssh_get_authentication_socket(); | 1704 | sock = ssh_get_authentication_socket(); |
@@ -1777,7 +1706,7 @@ client_request_agent(const char *request_type, int rchan) | |||
1777 | return NULL; | 1706 | return NULL; |
1778 | c = channel_new("authentication agent connection", | 1707 | c = channel_new("authentication agent connection", |
1779 | SSH_CHANNEL_OPEN, sock, sock, -1, | 1708 | SSH_CHANNEL_OPEN, sock, sock, -1, |
1780 | CHAN_X11_WINDOW_DEFAULT, CHAN_TCP_WINDOW_DEFAULT, 0, | 1709 | CHAN_X11_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, |
1781 | "authentication agent connection", 1); | 1710 | "authentication agent connection", 1); |
1782 | c->force_drain = 1; | 1711 | c->force_drain = 1; |
1783 | return c; | 1712 | return c; |
@@ -1812,7 +1741,7 @@ client_request_tun_fwd(int tun_mode, int local_tun, int remote_tun) | |||
1812 | #if defined(SSH_TUN_FILTER) | 1741 | #if defined(SSH_TUN_FILTER) |
1813 | if (options.tun_open == SSH_TUNMODE_POINTOPOINT) | 1742 | if (options.tun_open == SSH_TUNMODE_POINTOPOINT) |
1814 | channel_register_filter(c->self, sys_tun_infilter, | 1743 | channel_register_filter(c->self, sys_tun_infilter, |
1815 | sys_tun_outfilter); | 1744 | sys_tun_outfilter, NULL, NULL); |
1816 | #endif | 1745 | #endif |
1817 | 1746 | ||
1818 | packet_start(SSH2_MSG_CHANNEL_OPEN); | 1747 | packet_start(SSH2_MSG_CHANNEL_OPEN); |
@@ -1895,7 +1824,11 @@ client_input_channel_req(int type, u_int32_t seq, void *ctxt) | |||
1895 | if (id == -1) { | 1824 | if (id == -1) { |
1896 | error("client_input_channel_req: request for channel -1"); | 1825 | error("client_input_channel_req: request for channel -1"); |
1897 | } else if ((c = channel_lookup(id)) == NULL) { | 1826 | } else if ((c = channel_lookup(id)) == NULL) { |
1898 | error("client_input_channel_req: channel %d: unknown channel", id); | 1827 | error("client_input_channel_req: channel %d: " |
1828 | "unknown channel", id); | ||
1829 | } else if (strcmp(rtype, "eow@openssh.com") == 0) { | ||
1830 | packet_check_eom(); | ||
1831 | chan_rcvd_eow(c); | ||
1899 | } else if (strcmp(rtype, "exit-status") == 0) { | 1832 | } else if (strcmp(rtype, "exit-status") == 0) { |
1900 | exitval = packet_get_int(); | 1833 | exitval = packet_get_int(); |
1901 | if (id == session_ident) { | 1834 | if (id == session_ident) { |
@@ -1940,8 +1873,7 @@ client_input_global_request(int type, u_int32_t seq, void *ctxt) | |||
1940 | 1873 | ||
1941 | void | 1874 | void |
1942 | client_session2_setup(int id, int want_tty, int want_subsystem, | 1875 | client_session2_setup(int id, int want_tty, int want_subsystem, |
1943 | const char *term, struct termios *tiop, int in_fd, Buffer *cmd, char **env, | 1876 | const char *term, struct termios *tiop, int in_fd, Buffer *cmd, char **env) |
1944 | dispatch_fn *subsys_repl) | ||
1945 | { | 1877 | { |
1946 | int len; | 1878 | int len; |
1947 | Channel *c = NULL; | 1879 | Channel *c = NULL; |
@@ -1953,20 +1885,21 @@ client_session2_setup(int id, int want_tty, int want_subsystem, | |||
1953 | 1885 | ||
1954 | if (want_tty) { | 1886 | if (want_tty) { |
1955 | struct winsize ws; | 1887 | struct winsize ws; |
1956 | struct termios tio; | ||
1957 | 1888 | ||
1958 | /* Store window size in the packet. */ | 1889 | /* Store window size in the packet. */ |
1959 | if (ioctl(in_fd, TIOCGWINSZ, &ws) < 0) | 1890 | if (ioctl(in_fd, TIOCGWINSZ, &ws) < 0) |
1960 | memset(&ws, 0, sizeof(ws)); | 1891 | memset(&ws, 0, sizeof(ws)); |
1961 | 1892 | ||
1962 | channel_request_start(id, "pty-req", 0); | 1893 | channel_request_start(id, "pty-req", 1); |
1894 | client_expect_confirm(id, "PTY allocation", 0); | ||
1963 | packet_put_cstring(term != NULL ? term : ""); | 1895 | packet_put_cstring(term != NULL ? term : ""); |
1964 | packet_put_int((u_int)ws.ws_col); | 1896 | packet_put_int((u_int)ws.ws_col); |
1965 | packet_put_int((u_int)ws.ws_row); | 1897 | packet_put_int((u_int)ws.ws_row); |
1966 | packet_put_int((u_int)ws.ws_xpixel); | 1898 | packet_put_int((u_int)ws.ws_xpixel); |
1967 | packet_put_int((u_int)ws.ws_ypixel); | 1899 | packet_put_int((u_int)ws.ws_ypixel); |
1968 | tio = get_saved_tio(); | 1900 | if (tiop == NULL) |
1969 | tty_make_modes(-1, tiop != NULL ? tiop : &tio); | 1901 | tiop = get_saved_tio(); |
1902 | tty_make_modes(-1, tiop); | ||
1970 | packet_send(); | 1903 | packet_send(); |
1971 | /* XXX wait for reply */ | 1904 | /* XXX wait for reply */ |
1972 | c->client_tty = 1; | 1905 | c->client_tty = 1; |
@@ -2014,22 +1947,21 @@ client_session2_setup(int id, int want_tty, int want_subsystem, | |||
2014 | if (len > 900) | 1947 | if (len > 900) |
2015 | len = 900; | 1948 | len = 900; |
2016 | if (want_subsystem) { | 1949 | if (want_subsystem) { |
2017 | debug("Sending subsystem: %.*s", len, (u_char*)buffer_ptr(cmd)); | 1950 | debug("Sending subsystem: %.*s", |
2018 | channel_request_start(id, "subsystem", subsys_repl != NULL); | 1951 | len, (u_char*)buffer_ptr(cmd)); |
2019 | if (subsys_repl != NULL) { | 1952 | channel_request_start(id, "subsystem", 1); |
2020 | /* register callback for reply */ | 1953 | client_expect_confirm(id, "subsystem", 1); |
2021 | /* XXX we assume that client_loop has already been called */ | ||
2022 | dispatch_set(SSH2_MSG_CHANNEL_FAILURE, subsys_repl); | ||
2023 | dispatch_set(SSH2_MSG_CHANNEL_SUCCESS, subsys_repl); | ||
2024 | } | ||
2025 | } else { | 1954 | } else { |
2026 | debug("Sending command: %.*s", len, (u_char*)buffer_ptr(cmd)); | 1955 | debug("Sending command: %.*s", |
2027 | channel_request_start(id, "exec", 0); | 1956 | len, (u_char*)buffer_ptr(cmd)); |
1957 | channel_request_start(id, "exec", 1); | ||
1958 | client_expect_confirm(id, "exec", 1); | ||
2028 | } | 1959 | } |
2029 | packet_put_string(buffer_ptr(cmd), buffer_len(cmd)); | 1960 | packet_put_string(buffer_ptr(cmd), buffer_len(cmd)); |
2030 | packet_send(); | 1961 | packet_send(); |
2031 | } else { | 1962 | } else { |
2032 | channel_request_start(id, "shell", 0); | 1963 | channel_request_start(id, "shell", 1); |
1964 | client_expect_confirm(id, "shell", 1); | ||
2033 | packet_send(); | 1965 | packet_send(); |
2034 | } | 1966 | } |
2035 | } | 1967 | } |
@@ -2048,6 +1980,8 @@ client_init_dispatch_20(void) | |||
2048 | dispatch_set(SSH2_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure); | 1980 | dispatch_set(SSH2_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure); |
2049 | dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &client_input_channel_req); | 1981 | dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &client_input_channel_req); |
2050 | dispatch_set(SSH2_MSG_CHANNEL_WINDOW_ADJUST, &channel_input_window_adjust); | 1982 | dispatch_set(SSH2_MSG_CHANNEL_WINDOW_ADJUST, &channel_input_window_adjust); |
1983 | dispatch_set(SSH2_MSG_CHANNEL_SUCCESS, &channel_input_status_confirm); | ||
1984 | dispatch_set(SSH2_MSG_CHANNEL_FAILURE, &channel_input_status_confirm); | ||
2051 | dispatch_set(SSH2_MSG_GLOBAL_REQUEST, &client_input_global_request); | 1985 | dispatch_set(SSH2_MSG_GLOBAL_REQUEST, &client_input_global_request); |
2052 | 1986 | ||
2053 | /* rekeying */ | 1987 | /* rekeying */ |
@@ -2057,6 +1991,7 @@ client_init_dispatch_20(void) | |||
2057 | dispatch_set(SSH2_MSG_REQUEST_FAILURE, &client_global_request_reply); | 1991 | dispatch_set(SSH2_MSG_REQUEST_FAILURE, &client_global_request_reply); |
2058 | dispatch_set(SSH2_MSG_REQUEST_SUCCESS, &client_global_request_reply); | 1992 | dispatch_set(SSH2_MSG_REQUEST_SUCCESS, &client_global_request_reply); |
2059 | } | 1993 | } |
1994 | |||
2060 | static void | 1995 | static void |
2061 | client_init_dispatch_13(void) | 1996 | client_init_dispatch_13(void) |
2062 | { | 1997 | { |
@@ -2076,6 +2011,7 @@ client_init_dispatch_13(void) | |||
2076 | dispatch_set(SSH_SMSG_X11_OPEN, options.forward_x11 ? | 2011 | dispatch_set(SSH_SMSG_X11_OPEN, options.forward_x11 ? |
2077 | &x11_input_open : &deny_input_open); | 2012 | &x11_input_open : &deny_input_open); |
2078 | } | 2013 | } |
2014 | |||
2079 | static void | 2015 | static void |
2080 | client_init_dispatch_15(void) | 2016 | client_init_dispatch_15(void) |
2081 | { | 2017 | { |
@@ -2083,6 +2019,7 @@ client_init_dispatch_15(void) | |||
2083 | dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_ieof); | 2019 | dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_ieof); |
2084 | dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, & channel_input_oclose); | 2020 | dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, & channel_input_oclose); |
2085 | } | 2021 | } |
2022 | |||
2086 | static void | 2023 | static void |
2087 | client_init_dispatch(void) | 2024 | client_init_dispatch(void) |
2088 | { | 2025 | { |
@@ -2100,7 +2037,7 @@ cleanup_exit(int i) | |||
2100 | { | 2037 | { |
2101 | leave_raw_mode(); | 2038 | leave_raw_mode(); |
2102 | leave_non_blocking(); | 2039 | leave_non_blocking(); |
2103 | if (options.control_path != NULL && control_fd != -1) | 2040 | if (options.control_path != NULL && muxserver_sock != -1) |
2104 | unlink(options.control_path); | 2041 | unlink(options.control_path); |
2105 | _exit(i); | 2042 | _exit(i); |
2106 | } | 2043 | } |