diff options
Diffstat (limited to 'clientloop.c')
-rw-r--r-- | clientloop.c | 753 |
1 files changed, 345 insertions, 408 deletions
diff --git a/clientloop.c b/clientloop.c index 7037c4192..abe5609de 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,15 +480,26 @@ 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 (compat20) { | 501 | if (compat20) { |
478 | if (++server_alive_timeouts > options.server_alive_count_max) { | 502 | if (++keep_alive_timeouts > options.server_alive_count_max) { |
479 | logit("Timeout, server not responding."); | 503 | logit("Timeout, server not responding."); |
480 | cleanup_exit(255); | 504 | cleanup_exit(255); |
481 | } | 505 | } |
@@ -483,6 +507,8 @@ server_alive_check(void) | |||
483 | packet_put_cstring("keepalive@openssh.com"); | 507 | packet_put_cstring("keepalive@openssh.com"); |
484 | packet_put_char(1); /* boolean: want reply */ | 508 | packet_put_char(1); /* boolean: want reply */ |
485 | packet_send(); | 509 | packet_send(); |
510 | /* Insert an empty placeholder to maintain ordering */ | ||
511 | client_register_global_confirm(NULL, NULL); | ||
486 | } else { | 512 | } else { |
487 | packet_send_ignore(0); | 513 | packet_send_ignore(0); |
488 | packet_send(); | 514 | packet_send(); |
@@ -538,8 +564,8 @@ client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, | |||
538 | if (packet_have_data_to_write()) | 564 | if (packet_have_data_to_write()) |
539 | FD_SET(connection_out, *writesetp); | 565 | FD_SET(connection_out, *writesetp); |
540 | 566 | ||
541 | if (control_fd != -1) | 567 | if (muxserver_sock != -1) |
542 | FD_SET(control_fd, *readsetp); | 568 | FD_SET(muxserver_sock, *readsetp); |
543 | 569 | ||
544 | /* | 570 | /* |
545 | * Wait for something to happen. This will suspend the process until | 571 | * Wait for something to happen. This will suspend the process until |
@@ -581,9 +607,11 @@ client_suspend_self(Buffer *bin, Buffer *bout, Buffer *berr) | |||
581 | { | 607 | { |
582 | /* Flush stdout and stderr buffers. */ | 608 | /* Flush stdout and stderr buffers. */ |
583 | if (buffer_len(bout) > 0) | 609 | if (buffer_len(bout) > 0) |
584 | atomicio(vwrite, fileno(stdout), buffer_ptr(bout), buffer_len(bout)); | 610 | atomicio(vwrite, fileno(stdout), buffer_ptr(bout), |
611 | buffer_len(bout)); | ||
585 | if (buffer_len(berr) > 0) | 612 | if (buffer_len(berr) > 0) |
586 | atomicio(vwrite, fileno(stderr), buffer_ptr(berr), buffer_len(berr)); | 613 | atomicio(vwrite, fileno(stderr), buffer_ptr(berr), |
614 | buffer_len(berr)); | ||
587 | 615 | ||
588 | leave_raw_mode(); | 616 | leave_raw_mode(); |
589 | 617 | ||
@@ -623,9 +651,13 @@ client_process_net_input(fd_set *readset) | |||
623 | /* Read as much as possible. */ | 651 | /* Read as much as possible. */ |
624 | len = read(connection_in, buf, sizeof(buf)); | 652 | len = read(connection_in, buf, sizeof(buf)); |
625 | if (len == 0) { | 653 | if (len == 0) { |
626 | /* Received EOF. The remote host has closed the connection. */ | 654 | /* |
627 | snprintf(buf, sizeof buf, "Connection to %.300s closed by remote host.\r\n", | 655 | * Received EOF. The remote host has closed the |
628 | host); | 656 | * connection. |
657 | */ | ||
658 | snprintf(buf, sizeof buf, | ||
659 | "Connection to %.300s closed by remote host.\r\n", | ||
660 | host); | ||
629 | buffer_append(&stderr_buffer, buf, strlen(buf)); | 661 | buffer_append(&stderr_buffer, buf, strlen(buf)); |
630 | quit_pending = 1; | 662 | quit_pending = 1; |
631 | return; | 663 | return; |
@@ -634,13 +666,18 @@ client_process_net_input(fd_set *readset) | |||
634 | * There is a kernel bug on Solaris that causes select to | 666 | * There is a kernel bug on Solaris that causes select to |
635 | * sometimes wake up even though there is no data available. | 667 | * sometimes wake up even though there is no data available. |
636 | */ | 668 | */ |
637 | if (len < 0 && (errno == EAGAIN || errno == EINTR)) | 669 | if (len < 0 && |
670 | (errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK)) | ||
638 | len = 0; | 671 | len = 0; |
639 | 672 | ||
640 | if (len < 0) { | 673 | if (len < 0) { |
641 | /* An error has encountered. Perhaps there is a network problem. */ | 674 | /* |
642 | snprintf(buf, sizeof buf, "Read from remote host %.300s: %.100s\r\n", | 675 | * An error has encountered. Perhaps there is a |
643 | host, strerror(errno)); | 676 | * network problem. |
677 | */ | ||
678 | snprintf(buf, sizeof buf, | ||
679 | "Read from remote host %.300s: %.100s\r\n", | ||
680 | host, strerror(errno)); | ||
644 | buffer_append(&stderr_buffer, buf, strlen(buf)); | 681 | buffer_append(&stderr_buffer, buf, strlen(buf)); |
645 | quit_pending = 1; | 682 | quit_pending = 1; |
646 | return; | 683 | return; |
@@ -650,289 +687,81 @@ client_process_net_input(fd_set *readset) | |||
650 | } | 687 | } |
651 | 688 | ||
652 | static void | 689 | static void |
653 | client_subsystem_reply(int type, u_int32_t seq, void *ctxt) | 690 | client_status_confirm(int type, Channel *c, void *ctx) |
654 | { | 691 | { |
655 | int id; | 692 | struct channel_reply_ctx *cr = (struct channel_reply_ctx *)ctx; |
656 | Channel *c; | 693 | char errmsg[256]; |
657 | 694 | int tochan; | |
658 | id = packet_get_int(); | 695 | |
659 | packet_check_eom(); | 696 | /* XXX supress on mux _client_ quietmode */ |
660 | 697 | tochan = options.log_level >= SYSLOG_LEVEL_ERROR && | |
661 | if ((c = channel_lookup(id)) == NULL) { | 698 | c->ctl_fd != -1 && c->extended_usage == CHAN_EXTENDED_WRITE; |
662 | error("%s: no channel for id %d", __func__, id); | 699 | |
663 | return; | 700 | if (type == SSH2_MSG_CHANNEL_SUCCESS) { |
664 | } | 701 | debug2("%s request accepted on channel %d", |
665 | 702 | cr->request_type, c->self); | |
666 | if (type == SSH2_MSG_CHANNEL_SUCCESS) | 703 | } else if (type == SSH2_MSG_CHANNEL_FAILURE) { |
667 | debug2("Request suceeded on channel %d", id); | 704 | if (tochan) { |
668 | else if (type == SSH2_MSG_CHANNEL_FAILURE) { | 705 | snprintf(errmsg, sizeof(errmsg), |
669 | error("Request failed on channel %d", id); | 706 | "%s request failed\r\n", cr->request_type); |
670 | channel_free(c); | 707 | } else { |
708 | snprintf(errmsg, sizeof(errmsg), | ||
709 | "%s request failed on channel %d", | ||
710 | cr->request_type, c->self); | ||
711 | } | ||
712 | /* If error occurred on primary session channel, then exit */ | ||
713 | if (cr->do_close && c->self == session_ident) | ||
714 | fatal("%s", errmsg); | ||
715 | /* If error occurred on mux client, append to their stderr */ | ||
716 | if (tochan) | ||
717 | buffer_append(&c->extended, errmsg, strlen(errmsg)); | ||
718 | else | ||
719 | error("%s", errmsg); | ||
720 | if (cr->do_close) { | ||
721 | chan_read_failed(c); | ||
722 | chan_write_failed(c); | ||
723 | } | ||
671 | } | 724 | } |
725 | xfree(cr); | ||
672 | } | 726 | } |
673 | 727 | ||
674 | static void | 728 | static void |
675 | client_extra_session2_setup(int id, void *arg) | 729 | client_abandon_status_confirm(Channel *c, void *ctx) |
676 | { | 730 | { |
677 | struct confirm_ctx *cctx = arg; | 731 | xfree(ctx); |
678 | const char *display; | ||
679 | Channel *c; | ||
680 | int i; | ||
681 | |||
682 | if (cctx == NULL) | ||
683 | fatal("%s: cctx == NULL", __func__); | ||
684 | if ((c = channel_lookup(id)) == NULL) | ||
685 | fatal("%s: no channel for id %d", __func__, id); | ||
686 | |||
687 | display = getenv("DISPLAY"); | ||
688 | if (cctx->want_x_fwd && options.forward_x11 && display != NULL) { | ||
689 | char *proto, *data; | ||
690 | /* Get reasonable local authentication information. */ | ||
691 | client_x11_get_proto(display, options.xauth_location, | ||
692 | options.forward_x11_trusted, &proto, &data); | ||
693 | /* Request forwarding with authentication spoofing. */ | ||
694 | debug("Requesting X11 forwarding with authentication spoofing."); | ||
695 | x11_request_forwarding_with_spoofing(id, display, proto, data); | ||
696 | /* XXX wait for reply */ | ||
697 | } | ||
698 | |||
699 | if (cctx->want_agent_fwd && options.forward_agent) { | ||
700 | debug("Requesting authentication agent forwarding."); | ||
701 | channel_request_start(id, "auth-agent-req@openssh.com", 0); | ||
702 | packet_send(); | ||
703 | } | ||
704 | |||
705 | client_session2_setup(id, cctx->want_tty, cctx->want_subsys, | ||
706 | cctx->term, &cctx->tio, c->rfd, &cctx->cmd, cctx->env, | ||
707 | client_subsystem_reply); | ||
708 | |||
709 | c->confirm_ctx = NULL; | ||
710 | buffer_free(&cctx->cmd); | ||
711 | xfree(cctx->term); | ||
712 | if (cctx->env != NULL) { | ||
713 | for (i = 0; cctx->env[i] != NULL; i++) | ||
714 | xfree(cctx->env[i]); | ||
715 | xfree(cctx->env); | ||
716 | } | ||
717 | xfree(cctx); | ||
718 | } | 732 | } |
719 | 733 | ||
720 | static void | 734 | static void |
721 | client_process_control(fd_set *readset) | 735 | client_expect_confirm(int id, const char *request, int do_close) |
722 | { | 736 | { |
723 | Buffer m; | 737 | struct channel_reply_ctx *cr = xmalloc(sizeof(*cr)); |
724 | Channel *c; | ||
725 | int client_fd, new_fd[3], ver, allowed, window, packetmax; | ||
726 | socklen_t addrlen; | ||
727 | struct sockaddr_storage addr; | ||
728 | struct confirm_ctx *cctx; | ||
729 | char *cmd; | ||
730 | u_int i, len, env_len, command, flags; | ||
731 | uid_t euid; | ||
732 | gid_t egid; | ||
733 | |||
734 | /* | ||
735 | * Accept connection on control socket | ||
736 | */ | ||
737 | if (control_fd == -1 || !FD_ISSET(control_fd, readset)) | ||
738 | return; | ||
739 | |||
740 | memset(&addr, 0, sizeof(addr)); | ||
741 | addrlen = sizeof(addr); | ||
742 | if ((client_fd = accept(control_fd, | ||
743 | (struct sockaddr*)&addr, &addrlen)) == -1) { | ||
744 | error("%s accept: %s", __func__, strerror(errno)); | ||
745 | return; | ||
746 | } | ||
747 | |||
748 | if (getpeereid(client_fd, &euid, &egid) < 0) { | ||
749 | error("%s getpeereid failed: %s", __func__, strerror(errno)); | ||
750 | close(client_fd); | ||
751 | return; | ||
752 | } | ||
753 | if ((euid != 0) && (getuid() != euid)) { | ||
754 | error("control mode uid mismatch: peer euid %u != uid %u", | ||
755 | (u_int) euid, (u_int) getuid()); | ||
756 | close(client_fd); | ||
757 | return; | ||
758 | } | ||
759 | |||
760 | unset_nonblock(client_fd); | ||
761 | |||
762 | /* Read command */ | ||
763 | buffer_init(&m); | ||
764 | if (ssh_msg_recv(client_fd, &m) == -1) { | ||
765 | error("%s: client msg_recv failed", __func__); | ||
766 | close(client_fd); | ||
767 | buffer_free(&m); | ||
768 | return; | ||
769 | } | ||
770 | if ((ver = buffer_get_char(&m)) != SSHMUX_VER) { | ||
771 | error("%s: wrong client version %d", __func__, ver); | ||
772 | buffer_free(&m); | ||
773 | close(client_fd); | ||
774 | return; | ||
775 | } | ||
776 | |||
777 | allowed = 1; | ||
778 | command = buffer_get_int(&m); | ||
779 | flags = buffer_get_int(&m); | ||
780 | |||
781 | buffer_clear(&m); | ||
782 | |||
783 | switch (command) { | ||
784 | case SSHMUX_COMMAND_OPEN: | ||
785 | if (options.control_master == SSHCTL_MASTER_ASK || | ||
786 | options.control_master == SSHCTL_MASTER_AUTO_ASK) | ||
787 | allowed = ask_permission("Allow shared connection " | ||
788 | "to %s? ", host); | ||
789 | /* continue below */ | ||
790 | break; | ||
791 | case SSHMUX_COMMAND_TERMINATE: | ||
792 | if (options.control_master == SSHCTL_MASTER_ASK || | ||
793 | options.control_master == SSHCTL_MASTER_AUTO_ASK) | ||
794 | allowed = ask_permission("Terminate shared connection " | ||
795 | "to %s? ", host); | ||
796 | if (allowed) | ||
797 | quit_pending = 1; | ||
798 | /* FALLTHROUGH */ | ||
799 | case SSHMUX_COMMAND_ALIVE_CHECK: | ||
800 | /* Reply for SSHMUX_COMMAND_TERMINATE and ALIVE_CHECK */ | ||
801 | buffer_clear(&m); | ||
802 | buffer_put_int(&m, allowed); | ||
803 | buffer_put_int(&m, getpid()); | ||
804 | if (ssh_msg_send(client_fd, SSHMUX_VER, &m) == -1) { | ||
805 | error("%s: client msg_send failed", __func__); | ||
806 | close(client_fd); | ||
807 | buffer_free(&m); | ||
808 | return; | ||
809 | } | ||
810 | buffer_free(&m); | ||
811 | close(client_fd); | ||
812 | return; | ||
813 | default: | ||
814 | error("Unsupported command %d", command); | ||
815 | buffer_free(&m); | ||
816 | close(client_fd); | ||
817 | return; | ||
818 | } | ||
819 | |||
820 | /* Reply for SSHMUX_COMMAND_OPEN */ | ||
821 | buffer_clear(&m); | ||
822 | buffer_put_int(&m, allowed); | ||
823 | buffer_put_int(&m, getpid()); | ||
824 | if (ssh_msg_send(client_fd, SSHMUX_VER, &m) == -1) { | ||
825 | error("%s: client msg_send failed", __func__); | ||
826 | close(client_fd); | ||
827 | buffer_free(&m); | ||
828 | return; | ||
829 | } | ||
830 | |||
831 | if (!allowed) { | ||
832 | error("Refused control connection"); | ||
833 | close(client_fd); | ||
834 | buffer_free(&m); | ||
835 | return; | ||
836 | } | ||
837 | 738 | ||
838 | buffer_clear(&m); | 739 | cr->request_type = request; |
839 | if (ssh_msg_recv(client_fd, &m) == -1) { | 740 | cr->do_close = do_close; |
840 | error("%s: client msg_recv failed", __func__); | ||
841 | close(client_fd); | ||
842 | buffer_free(&m); | ||
843 | return; | ||
844 | } | ||
845 | if ((ver = buffer_get_char(&m)) != SSHMUX_VER) { | ||
846 | error("%s: wrong client version %d", __func__, ver); | ||
847 | buffer_free(&m); | ||
848 | close(client_fd); | ||
849 | return; | ||
850 | } | ||
851 | 741 | ||
852 | cctx = xcalloc(1, sizeof(*cctx)); | 742 | channel_register_status_confirm(id, client_status_confirm, |
853 | cctx->want_tty = (flags & SSHMUX_FLAG_TTY) != 0; | 743 | client_abandon_status_confirm, cr); |
854 | cctx->want_subsys = (flags & SSHMUX_FLAG_SUBSYS) != 0; | 744 | } |
855 | cctx->want_x_fwd = (flags & SSHMUX_FLAG_X11_FWD) != 0; | ||
856 | cctx->want_agent_fwd = (flags & SSHMUX_FLAG_AGENT_FWD) != 0; | ||
857 | cctx->term = buffer_get_string(&m, &len); | ||
858 | |||
859 | cmd = buffer_get_string(&m, &len); | ||
860 | buffer_init(&cctx->cmd); | ||
861 | buffer_append(&cctx->cmd, cmd, strlen(cmd)); | ||
862 | |||
863 | env_len = buffer_get_int(&m); | ||
864 | env_len = MIN(env_len, 4096); | ||
865 | debug3("%s: receiving %d env vars", __func__, env_len); | ||
866 | if (env_len != 0) { | ||
867 | cctx->env = xcalloc(env_len + 1, sizeof(*cctx->env)); | ||
868 | for (i = 0; i < env_len; i++) | ||
869 | cctx->env[i] = buffer_get_string(&m, &len); | ||
870 | cctx->env[i] = NULL; | ||
871 | } | ||
872 | 745 | ||
873 | debug2("%s: accepted tty %d, subsys %d, cmd %s", __func__, | 746 | void |
874 | cctx->want_tty, cctx->want_subsys, cmd); | 747 | client_register_global_confirm(global_confirm_cb *cb, void *ctx) |
875 | xfree(cmd); | 748 | { |
876 | 749 | struct global_confirm *gc, *last_gc; | |
877 | /* Gather fds from client */ | 750 | |
878 | new_fd[0] = mm_receive_fd(client_fd); | 751 | /* Coalesce identical callbacks */ |
879 | new_fd[1] = mm_receive_fd(client_fd); | 752 | last_gc = TAILQ_LAST(&global_confirms, global_confirms); |
880 | new_fd[2] = mm_receive_fd(client_fd); | 753 | if (last_gc && last_gc->cb == cb && last_gc->ctx == ctx) { |
881 | 754 | if (++last_gc->ref_count >= INT_MAX) | |
882 | debug2("%s: got fds stdin %d, stdout %d, stderr %d", __func__, | 755 | fatal("%s: last_gc->ref_count = %d", |
883 | new_fd[0], new_fd[1], new_fd[2]); | 756 | __func__, last_gc->ref_count); |
884 | |||
885 | /* Try to pick up ttymodes from client before it goes raw */ | ||
886 | if (cctx->want_tty && tcgetattr(new_fd[0], &cctx->tio) == -1) | ||
887 | error("%s: tcgetattr: %s", __func__, strerror(errno)); | ||
888 | |||
889 | /* This roundtrip is just for synchronisation of ttymodes */ | ||
890 | buffer_clear(&m); | ||
891 | if (ssh_msg_send(client_fd, SSHMUX_VER, &m) == -1) { | ||
892 | error("%s: client msg_send failed", __func__); | ||
893 | close(client_fd); | ||
894 | close(new_fd[0]); | ||
895 | close(new_fd[1]); | ||
896 | close(new_fd[2]); | ||
897 | buffer_free(&m); | ||
898 | xfree(cctx->term); | ||
899 | if (env_len != 0) { | ||
900 | for (i = 0; i < env_len; i++) | ||
901 | xfree(cctx->env[i]); | ||
902 | xfree(cctx->env); | ||
903 | } | ||
904 | return; | 757 | return; |
905 | } | 758 | } |
906 | buffer_free(&m); | ||
907 | |||
908 | /* enable nonblocking unless tty */ | ||
909 | if (!isatty(new_fd[0])) | ||
910 | set_nonblock(new_fd[0]); | ||
911 | if (!isatty(new_fd[1])) | ||
912 | set_nonblock(new_fd[1]); | ||
913 | if (!isatty(new_fd[2])) | ||
914 | set_nonblock(new_fd[2]); | ||
915 | |||
916 | set_nonblock(client_fd); | ||
917 | |||
918 | window = CHAN_SES_WINDOW_DEFAULT; | ||
919 | packetmax = CHAN_SES_PACKET_DEFAULT; | ||
920 | if (cctx->want_tty) { | ||
921 | window >>= 1; | ||
922 | packetmax >>= 1; | ||
923 | } | ||
924 | |||
925 | c = channel_new("session", SSH_CHANNEL_OPENING, | ||
926 | new_fd[0], new_fd[1], new_fd[2], window, packetmax, | ||
927 | CHAN_EXTENDED_WRITE, "client-session", /*nonblock*/0); | ||
928 | 759 | ||
929 | /* XXX */ | 760 | gc = xmalloc(sizeof(*gc)); |
930 | c->ctl_fd = client_fd; | 761 | gc->cb = cb; |
931 | 762 | gc->ctx = ctx; | |
932 | debug3("%s: channel_new: %d", __func__, c->self); | 763 | gc->ref_count = 1; |
933 | 764 | TAILQ_INSERT_TAIL(&global_confirms, gc, entry); | |
934 | channel_send_open(c->self); | ||
935 | channel_register_confirm(c->self, client_extra_session2_setup, cctx); | ||
936 | } | 765 | } |
937 | 766 | ||
938 | static void | 767 | static void |
@@ -945,6 +774,9 @@ process_cmdline(void) | |||
945 | u_short cancel_port; | 774 | u_short cancel_port; |
946 | Forward fwd; | 775 | Forward fwd; |
947 | 776 | ||
777 | bzero(&fwd, sizeof(fwd)); | ||
778 | fwd.listen_host = fwd.connect_host = NULL; | ||
779 | |||
948 | leave_raw_mode(); | 780 | leave_raw_mode(); |
949 | handler = signal(SIGINT, SIG_IGN); | 781 | handler = signal(SIGINT, SIG_IGN); |
950 | cmd = s = read_passphrase("\r\nssh> ", RP_ECHO); | 782 | cmd = s = read_passphrase("\r\nssh> ", RP_ECHO); |
@@ -1044,11 +876,18 @@ out: | |||
1044 | enter_raw_mode(); | 876 | enter_raw_mode(); |
1045 | if (cmd) | 877 | if (cmd) |
1046 | xfree(cmd); | 878 | xfree(cmd); |
879 | if (fwd.listen_host != NULL) | ||
880 | xfree(fwd.listen_host); | ||
881 | if (fwd.connect_host != NULL) | ||
882 | xfree(fwd.connect_host); | ||
1047 | } | 883 | } |
1048 | 884 | ||
1049 | /* process the characters one by one */ | 885 | /* |
886 | * Process the characters one by one, call with c==NULL for proto1 case. | ||
887 | */ | ||
1050 | static int | 888 | static int |
1051 | process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len) | 889 | process_escapes(Channel *c, Buffer *bin, Buffer *bout, Buffer *berr, |
890 | char *buf, int len) | ||
1052 | { | 891 | { |
1053 | char string[1024]; | 892 | char string[1024]; |
1054 | pid_t pid; | 893 | pid_t pid; |
@@ -1056,7 +895,20 @@ process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len) | |||
1056 | u_int i; | 895 | u_int i; |
1057 | u_char ch; | 896 | u_char ch; |
1058 | char *s; | 897 | char *s; |
898 | int *escape_pendingp, escape_char; | ||
899 | struct escape_filter_ctx *efc; | ||
1059 | 900 | ||
901 | if (c == NULL) { | ||
902 | escape_pendingp = &escape_pending1; | ||
903 | escape_char = escape_char1; | ||
904 | } else { | ||
905 | if (c->filter_ctx == NULL) | ||
906 | return 0; | ||
907 | efc = (struct escape_filter_ctx *)c->filter_ctx; | ||
908 | escape_pendingp = &efc->escape_pending; | ||
909 | escape_char = efc->escape_char; | ||
910 | } | ||
911 | |||
1060 | if (len <= 0) | 912 | if (len <= 0) |
1061 | return (0); | 913 | return (0); |
1062 | 914 | ||
@@ -1064,25 +916,42 @@ process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len) | |||
1064 | /* Get one character at a time. */ | 916 | /* Get one character at a time. */ |
1065 | ch = buf[i]; | 917 | ch = buf[i]; |
1066 | 918 | ||
1067 | if (escape_pending) { | 919 | if (*escape_pendingp) { |
1068 | /* We have previously seen an escape character. */ | 920 | /* We have previously seen an escape character. */ |
1069 | /* Clear the flag now. */ | 921 | /* Clear the flag now. */ |
1070 | escape_pending = 0; | 922 | *escape_pendingp = 0; |
1071 | 923 | ||
1072 | /* Process the escaped character. */ | 924 | /* Process the escaped character. */ |
1073 | switch (ch) { | 925 | switch (ch) { |
1074 | case '.': | 926 | case '.': |
1075 | /* Terminate the connection. */ | 927 | /* Terminate the connection. */ |
1076 | snprintf(string, sizeof string, "%c.\r\n", escape_char); | 928 | snprintf(string, sizeof string, "%c.\r\n", |
929 | escape_char); | ||
1077 | buffer_append(berr, string, strlen(string)); | 930 | buffer_append(berr, string, strlen(string)); |
1078 | 931 | ||
1079 | quit_pending = 1; | 932 | if (c && c->ctl_fd != -1) { |
933 | chan_read_failed(c); | ||
934 | chan_write_failed(c); | ||
935 | return 0; | ||
936 | } else | ||
937 | quit_pending = 1; | ||
1080 | return -1; | 938 | return -1; |
1081 | 939 | ||
1082 | case 'Z' - 64: | 940 | case 'Z' - 64: |
1083 | /* Suspend the program. */ | 941 | /* XXX support this for mux clients */ |
1084 | /* Print a message to that effect to the user. */ | 942 | if (c && c->ctl_fd != -1) { |
1085 | snprintf(string, sizeof string, "%c^Z [suspend ssh]\r\n", escape_char); | 943 | noescape: |
944 | snprintf(string, sizeof string, | ||
945 | "%c%c escape not available to " | ||
946 | "multiplexed sessions\r\n", | ||
947 | escape_char, ch); | ||
948 | buffer_append(berr, string, | ||
949 | strlen(string)); | ||
950 | continue; | ||
951 | } | ||
952 | /* Suspend the program. Inform the user */ | ||
953 | snprintf(string, sizeof string, | ||
954 | "%c^Z [suspend ssh]\r\n", escape_char); | ||
1086 | buffer_append(berr, string, strlen(string)); | 955 | buffer_append(berr, string, strlen(string)); |
1087 | 956 | ||
1088 | /* Restore terminal modes and suspend. */ | 957 | /* Restore terminal modes and suspend. */ |
@@ -1107,16 +976,20 @@ process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len) | |||
1107 | case 'R': | 976 | case 'R': |
1108 | if (compat20) { | 977 | if (compat20) { |
1109 | if (datafellows & SSH_BUG_NOREKEY) | 978 | if (datafellows & SSH_BUG_NOREKEY) |
1110 | logit("Server does not support re-keying"); | 979 | logit("Server does not " |
980 | "support re-keying"); | ||
1111 | else | 981 | else |
1112 | need_rekeying = 1; | 982 | need_rekeying = 1; |
1113 | } | 983 | } |
1114 | continue; | 984 | continue; |
1115 | 985 | ||
1116 | case '&': | 986 | case '&': |
987 | if (c && c->ctl_fd != -1) | ||
988 | goto noescape; | ||
1117 | /* | 989 | /* |
1118 | * Detach the program (continue to serve connections, | 990 | * Detach the program (continue to serve |
1119 | * but put in background and no more new connections). | 991 | * connections, but put in background and no |
992 | * more new connections). | ||
1120 | */ | 993 | */ |
1121 | /* Restore tty modes. */ | 994 | /* Restore tty modes. */ |
1122 | leave_raw_mode(); | 995 | leave_raw_mode(); |
@@ -1145,9 +1018,9 @@ process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len) | |||
1145 | return -1; | 1018 | return -1; |
1146 | } else if (!stdin_eof) { | 1019 | } else if (!stdin_eof) { |
1147 | /* | 1020 | /* |
1148 | * Sending SSH_CMSG_EOF alone does not always appear | 1021 | * Sending SSH_CMSG_EOF alone does not |
1149 | * to be enough. So we try to send an EOF character | 1022 | * always appear to be enough. So we |
1150 | * first. | 1023 | * try to send an EOF character first. |
1151 | */ | 1024 | */ |
1152 | packet_start(SSH_CMSG_STDIN_DATA); | 1025 | packet_start(SSH_CMSG_STDIN_DATA); |
1153 | packet_put_string("\004", 1); | 1026 | packet_put_string("\004", 1); |
@@ -1162,27 +1035,50 @@ process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len) | |||
1162 | continue; | 1035 | continue; |
1163 | 1036 | ||
1164 | case '?': | 1037 | case '?': |
1165 | snprintf(string, sizeof string, | 1038 | if (c && c->ctl_fd != -1) { |
1039 | snprintf(string, sizeof string, | ||
1166 | "%c?\r\n\ | 1040 | "%c?\r\n\ |
1167 | Supported escape sequences:\r\n\ | 1041 | Supported escape sequences:\r\n\ |
1168 | %c. - terminate connection\r\n\ | 1042 | %c. - terminate session\r\n\ |
1169 | %cB - send a BREAK to the remote system\r\n\ | 1043 | %cB - send a BREAK to the remote system\r\n\ |
1170 | %cC - open a command line\r\n\ | 1044 | %cC - open a command line\r\n\ |
1171 | %cR - Request rekey (SSH protocol 2 only)\r\n\ | 1045 | %cR - Request rekey (SSH protocol 2 only)\r\n\ |
1172 | %c^Z - suspend ssh\r\n\ | 1046 | %c# - list forwarded connections\r\n\ |
1173 | %c# - list forwarded connections\r\n\ | 1047 | %c? - this message\r\n\ |
1174 | %c& - background ssh (when waiting for connections to terminate)\r\n\ | 1048 | %c%c - send the escape character by typing it twice\r\n\ |
1175 | %c? - this message\r\n\ | ||
1176 | %c%c - send the escape character by typing it twice\r\n\ | ||
1177 | (Note that escapes are only recognized immediately after newline.)\r\n", | 1049 | (Note that escapes are only recognized immediately after newline.)\r\n", |
1178 | escape_char, escape_char, escape_char, escape_char, | 1050 | escape_char, escape_char, |
1179 | escape_char, escape_char, escape_char, escape_char, | 1051 | escape_char, escape_char, |
1180 | escape_char, escape_char, escape_char); | 1052 | escape_char, escape_char, |
1053 | escape_char, escape_char, | ||
1054 | escape_char); | ||
1055 | } else { | ||
1056 | snprintf(string, sizeof string, | ||
1057 | "%c?\r\n\ | ||
1058 | Supported escape sequences:\r\n\ | ||
1059 | %c. - terminate connection (and any multiplexed sessions)\r\n\ | ||
1060 | %cB - send a BREAK to the remote system\r\n\ | ||
1061 | %cC - open a command line\r\n\ | ||
1062 | %cR - Request rekey (SSH protocol 2 only)\r\n\ | ||
1063 | %c^Z - suspend ssh\r\n\ | ||
1064 | %c# - list forwarded connections\r\n\ | ||
1065 | %c& - background ssh (when waiting for connections to terminate)\r\n\ | ||
1066 | %c? - this message\r\n\ | ||
1067 | %c%c - send the escape character by typing it twice\r\n\ | ||
1068 | (Note that escapes are only recognized immediately after newline.)\r\n", | ||
1069 | escape_char, escape_char, | ||
1070 | escape_char, escape_char, | ||
1071 | escape_char, escape_char, | ||
1072 | escape_char, escape_char, | ||
1073 | escape_char, escape_char, | ||
1074 | escape_char); | ||
1075 | } | ||
1181 | buffer_append(berr, string, strlen(string)); | 1076 | buffer_append(berr, string, strlen(string)); |
1182 | continue; | 1077 | continue; |
1183 | 1078 | ||
1184 | case '#': | 1079 | case '#': |
1185 | snprintf(string, sizeof string, "%c#\r\n", escape_char); | 1080 | snprintf(string, sizeof string, "%c#\r\n", |
1081 | escape_char); | ||
1186 | buffer_append(berr, string, strlen(string)); | 1082 | buffer_append(berr, string, strlen(string)); |
1187 | s = channel_open_message(); | 1083 | s = channel_open_message(); |
1188 | buffer_append(berr, s, strlen(s)); | 1084 | buffer_append(berr, s, strlen(s)); |
@@ -1203,12 +1099,15 @@ Supported escape sequences:\r\n\ | |||
1203 | } | 1099 | } |
1204 | } else { | 1100 | } else { |
1205 | /* | 1101 | /* |
1206 | * The previous character was not an escape char. Check if this | 1102 | * The previous character was not an escape char. |
1207 | * is an escape. | 1103 | * Check if this is an escape. |
1208 | */ | 1104 | */ |
1209 | if (last_was_cr && ch == escape_char) { | 1105 | if (last_was_cr && ch == escape_char) { |
1210 | /* It is. Set the flag and continue to next character. */ | 1106 | /* |
1211 | escape_pending = 1; | 1107 | * It is. Set the flag and continue to |
1108 | * next character. | ||
1109 | */ | ||
1110 | *escape_pendingp = 1; | ||
1212 | continue; | 1111 | continue; |
1213 | } | 1112 | } |
1214 | } | 1113 | } |
@@ -1234,7 +1133,8 @@ client_process_input(fd_set *readset) | |||
1234 | if (FD_ISSET(fileno(stdin), readset)) { | 1133 | if (FD_ISSET(fileno(stdin), readset)) { |
1235 | /* Read as much as possible. */ | 1134 | /* Read as much as possible. */ |
1236 | len = read(fileno(stdin), buf, sizeof(buf)); | 1135 | len = read(fileno(stdin), buf, sizeof(buf)); |
1237 | if (len < 0 && (errno == EAGAIN || errno == EINTR)) | 1136 | if (len < 0 && |
1137 | (errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK)) | ||
1238 | return; /* we'll try again later */ | 1138 | return; /* we'll try again later */ |
1239 | if (len <= 0) { | 1139 | if (len <= 0) { |
1240 | /* | 1140 | /* |
@@ -1243,7 +1143,8 @@ client_process_input(fd_set *readset) | |||
1243 | * if it was an error condition. | 1143 | * if it was an error condition. |
1244 | */ | 1144 | */ |
1245 | if (len < 0) { | 1145 | if (len < 0) { |
1246 | snprintf(buf, sizeof buf, "read: %.100s\r\n", strerror(errno)); | 1146 | snprintf(buf, sizeof buf, "read: %.100s\r\n", |
1147 | strerror(errno)); | ||
1247 | buffer_append(&stderr_buffer, buf, strlen(buf)); | 1148 | buffer_append(&stderr_buffer, buf, strlen(buf)); |
1248 | } | 1149 | } |
1249 | /* Mark that we have seen EOF. */ | 1150 | /* Mark that we have seen EOF. */ |
@@ -1259,7 +1160,7 @@ client_process_input(fd_set *readset) | |||
1259 | packet_start(SSH_CMSG_EOF); | 1160 | packet_start(SSH_CMSG_EOF); |
1260 | packet_send(); | 1161 | packet_send(); |
1261 | } | 1162 | } |
1262 | } else if (escape_char == SSH_ESCAPECHAR_NONE) { | 1163 | } else if (escape_char1 == SSH_ESCAPECHAR_NONE) { |
1263 | /* | 1164 | /* |
1264 | * Normal successful read, and no escape character. | 1165 | * Normal successful read, and no escape character. |
1265 | * Just append the data to buffer. | 1166 | * Just append the data to buffer. |
@@ -1267,11 +1168,12 @@ client_process_input(fd_set *readset) | |||
1267 | buffer_append(&stdin_buffer, buf, len); | 1168 | buffer_append(&stdin_buffer, buf, len); |
1268 | } else { | 1169 | } else { |
1269 | /* | 1170 | /* |
1270 | * Normal, successful read. But we have an escape character | 1171 | * Normal, successful read. But we have an escape |
1271 | * and have to process the characters one by one. | 1172 | * character and have to process the characters one |
1173 | * by one. | ||
1272 | */ | 1174 | */ |
1273 | if (process_escapes(&stdin_buffer, &stdout_buffer, | 1175 | if (process_escapes(NULL, &stdin_buffer, |
1274 | &stderr_buffer, buf, len) == -1) | 1176 | &stdout_buffer, &stderr_buffer, buf, len) == -1) |
1275 | return; | 1177 | return; |
1276 | } | 1178 | } |
1277 | } | 1179 | } |
@@ -1289,14 +1191,16 @@ client_process_output(fd_set *writeset) | |||
1289 | len = write(fileno(stdout), buffer_ptr(&stdout_buffer), | 1191 | len = write(fileno(stdout), buffer_ptr(&stdout_buffer), |
1290 | buffer_len(&stdout_buffer)); | 1192 | buffer_len(&stdout_buffer)); |
1291 | if (len <= 0) { | 1193 | if (len <= 0) { |
1292 | if (errno == EINTR || errno == EAGAIN) | 1194 | if (errno == EINTR || errno == EAGAIN || |
1195 | errno == EWOULDBLOCK) | ||
1293 | len = 0; | 1196 | len = 0; |
1294 | else { | 1197 | else { |
1295 | /* | 1198 | /* |
1296 | * An error or EOF was encountered. Put an | 1199 | * An error or EOF was encountered. Put an |
1297 | * error message to stderr buffer. | 1200 | * error message to stderr buffer. |
1298 | */ | 1201 | */ |
1299 | snprintf(buf, sizeof buf, "write stdout: %.50s\r\n", strerror(errno)); | 1202 | snprintf(buf, sizeof buf, |
1203 | "write stdout: %.50s\r\n", strerror(errno)); | ||
1300 | buffer_append(&stderr_buffer, buf, strlen(buf)); | 1204 | buffer_append(&stderr_buffer, buf, strlen(buf)); |
1301 | quit_pending = 1; | 1205 | quit_pending = 1; |
1302 | return; | 1206 | return; |
@@ -1304,7 +1208,6 @@ client_process_output(fd_set *writeset) | |||
1304 | } | 1208 | } |
1305 | /* Consume printed data from the buffer. */ | 1209 | /* Consume printed data from the buffer. */ |
1306 | buffer_consume(&stdout_buffer, len); | 1210 | buffer_consume(&stdout_buffer, len); |
1307 | stdout_bytes += len; | ||
1308 | } | 1211 | } |
1309 | /* Write buffered output to stderr. */ | 1212 | /* Write buffered output to stderr. */ |
1310 | if (FD_ISSET(fileno(stderr), writeset)) { | 1213 | if (FD_ISSET(fileno(stderr), writeset)) { |
@@ -1312,17 +1215,20 @@ client_process_output(fd_set *writeset) | |||
1312 | len = write(fileno(stderr), buffer_ptr(&stderr_buffer), | 1215 | len = write(fileno(stderr), buffer_ptr(&stderr_buffer), |
1313 | buffer_len(&stderr_buffer)); | 1216 | buffer_len(&stderr_buffer)); |
1314 | if (len <= 0) { | 1217 | if (len <= 0) { |
1315 | if (errno == EINTR || errno == EAGAIN) | 1218 | if (errno == EINTR || errno == EAGAIN || |
1219 | errno == EWOULDBLOCK) | ||
1316 | len = 0; | 1220 | len = 0; |
1317 | else { | 1221 | else { |
1318 | /* EOF or error, but can't even print error message. */ | 1222 | /* |
1223 | * EOF or error, but can't even print | ||
1224 | * error message. | ||
1225 | */ | ||
1319 | quit_pending = 1; | 1226 | quit_pending = 1; |
1320 | return; | 1227 | return; |
1321 | } | 1228 | } |
1322 | } | 1229 | } |
1323 | /* Consume printed characters from the buffer. */ | 1230 | /* Consume printed characters from the buffer. */ |
1324 | buffer_consume(&stderr_buffer, len); | 1231 | buffer_consume(&stderr_buffer, len); |
1325 | stderr_bytes += len; | ||
1326 | } | 1232 | } |
1327 | } | 1233 | } |
1328 | 1234 | ||
@@ -1341,16 +1247,39 @@ client_process_output(fd_set *writeset) | |||
1341 | static void | 1247 | static void |
1342 | client_process_buffered_input_packets(void) | 1248 | client_process_buffered_input_packets(void) |
1343 | { | 1249 | { |
1344 | dispatch_run(DISPATCH_NONBLOCK, &quit_pending, compat20 ? xxx_kex : NULL); | 1250 | dispatch_run(DISPATCH_NONBLOCK, &quit_pending, |
1251 | compat20 ? xxx_kex : NULL); | ||
1345 | } | 1252 | } |
1346 | 1253 | ||
1347 | /* scan buf[] for '~' before sending data to the peer */ | 1254 | /* scan buf[] for '~' before sending data to the peer */ |
1348 | 1255 | ||
1349 | static int | 1256 | /* Helper: allocate a new escape_filter_ctx and fill in its escape char */ |
1350 | simple_escape_filter(Channel *c, char *buf, int len) | 1257 | void * |
1258 | client_new_escape_filter_ctx(int escape_char) | ||
1259 | { | ||
1260 | struct escape_filter_ctx *ret; | ||
1261 | |||
1262 | ret = xmalloc(sizeof(*ret)); | ||
1263 | ret->escape_pending = 0; | ||
1264 | ret->escape_char = escape_char; | ||
1265 | return (void *)ret; | ||
1266 | } | ||
1267 | |||
1268 | /* Free the escape filter context on channel free */ | ||
1269 | void | ||
1270 | client_filter_cleanup(int cid, void *ctx) | ||
1271 | { | ||
1272 | xfree(ctx); | ||
1273 | } | ||
1274 | |||
1275 | int | ||
1276 | client_simple_escape_filter(Channel *c, char *buf, int len) | ||
1351 | { | 1277 | { |
1352 | /* XXX we assume c->extended is writeable */ | 1278 | if (c->extended_usage != CHAN_EXTENDED_WRITE) |
1353 | return process_escapes(&c->input, &c->output, &c->extended, buf, len); | 1279 | return 0; |
1280 | |||
1281 | return process_escapes(c, &c->input, &c->output, &c->extended, | ||
1282 | buf, len); | ||
1354 | } | 1283 | } |
1355 | 1284 | ||
1356 | static void | 1285 | static void |
@@ -1374,6 +1303,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1374 | fd_set *readset = NULL, *writeset = NULL; | 1303 | fd_set *readset = NULL, *writeset = NULL; |
1375 | double start_time, total_time; | 1304 | double start_time, total_time; |
1376 | int max_fd = 0, max_fd2 = 0, len, rekeying = 0; | 1305 | int max_fd = 0, max_fd2 = 0, len, rekeying = 0; |
1306 | u_int64_t ibytes, obytes; | ||
1377 | u_int nalloc = 0; | 1307 | u_int nalloc = 0; |
1378 | char buf[100]; | 1308 | char buf[100]; |
1379 | 1309 | ||
@@ -1382,7 +1312,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1382 | start_time = get_current_time(); | 1312 | start_time = get_current_time(); |
1383 | 1313 | ||
1384 | /* Initialize variables. */ | 1314 | /* Initialize variables. */ |
1385 | escape_pending = 0; | 1315 | escape_pending1 = 0; |
1386 | last_was_cr = 1; | 1316 | last_was_cr = 1; |
1387 | exit_status = -1; | 1317 | exit_status = -1; |
1388 | stdin_eof = 0; | 1318 | stdin_eof = 0; |
@@ -1390,8 +1320,8 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1390 | connection_in = packet_get_connection_in(); | 1320 | connection_in = packet_get_connection_in(); |
1391 | connection_out = packet_get_connection_out(); | 1321 | connection_out = packet_get_connection_out(); |
1392 | max_fd = MAX(connection_in, connection_out); | 1322 | max_fd = MAX(connection_in, connection_out); |
1393 | if (control_fd != -1) | 1323 | if (muxserver_sock != -1) |
1394 | max_fd = MAX(max_fd, control_fd); | 1324 | max_fd = MAX(max_fd, muxserver_sock); |
1395 | 1325 | ||
1396 | if (!compat20) { | 1326 | if (!compat20) { |
1397 | /* enable nonblocking unless tty */ | 1327 | /* enable nonblocking unless tty */ |
@@ -1405,11 +1335,8 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1405 | max_fd = MAX(max_fd, fileno(stdout)); | 1335 | max_fd = MAX(max_fd, fileno(stdout)); |
1406 | max_fd = MAX(max_fd, fileno(stderr)); | 1336 | max_fd = MAX(max_fd, fileno(stderr)); |
1407 | } | 1337 | } |
1408 | stdin_bytes = 0; | ||
1409 | stdout_bytes = 0; | ||
1410 | stderr_bytes = 0; | ||
1411 | quit_pending = 0; | 1338 | quit_pending = 0; |
1412 | escape_char = escape_char_arg; | 1339 | escape_char1 = escape_char_arg; |
1413 | 1340 | ||
1414 | /* Initialize buffers. */ | 1341 | /* Initialize buffers. */ |
1415 | buffer_init(&stdin_buffer); | 1342 | buffer_init(&stdin_buffer); |
@@ -1437,9 +1364,11 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1437 | 1364 | ||
1438 | if (compat20) { | 1365 | if (compat20) { |
1439 | session_ident = ssh2_chan_id; | 1366 | session_ident = ssh2_chan_id; |
1440 | if (escape_char != SSH_ESCAPECHAR_NONE) | 1367 | if (escape_char_arg != SSH_ESCAPECHAR_NONE) |
1441 | channel_register_filter(session_ident, | 1368 | channel_register_filter(session_ident, |
1442 | simple_escape_filter, NULL); | 1369 | client_simple_escape_filter, NULL, |
1370 | client_filter_cleanup, | ||
1371 | client_new_escape_filter_ctx(escape_char_arg)); | ||
1443 | if (session_ident != -1) | 1372 | if (session_ident != -1) |
1444 | channel_register_cleanup(session_ident, | 1373 | channel_register_cleanup(session_ident, |
1445 | client_channel_closed, 0); | 1374 | client_channel_closed, 0); |
@@ -1511,7 +1440,10 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1511 | client_process_net_input(readset); | 1440 | client_process_net_input(readset); |
1512 | 1441 | ||
1513 | /* Accept control connections. */ | 1442 | /* Accept control connections. */ |
1514 | client_process_control(readset); | 1443 | if (muxserver_sock != -1 &&FD_ISSET(muxserver_sock, readset)) { |
1444 | if (muxserver_accept_control()) | ||
1445 | quit_pending = 1; | ||
1446 | } | ||
1515 | 1447 | ||
1516 | if (quit_pending) | 1448 | if (quit_pending) |
1517 | break; | 1449 | break; |
@@ -1526,7 +1458,10 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1526 | client_process_output(writeset); | 1458 | client_process_output(writeset); |
1527 | } | 1459 | } |
1528 | 1460 | ||
1529 | /* Send as much buffered packet data as possible to the sender. */ | 1461 | /* |
1462 | * Send as much buffered packet data as possible to the | ||
1463 | * sender. | ||
1464 | */ | ||
1530 | if (FD_ISSET(connection_out, writeset)) | 1465 | if (FD_ISSET(connection_out, writeset)) |
1531 | packet_write_poll(); | 1466 | packet_write_poll(); |
1532 | } | 1467 | } |
@@ -1573,7 +1508,8 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1573 | * that the connection has been closed. | 1508 | * that the connection has been closed. |
1574 | */ | 1509 | */ |
1575 | if (have_pty && options.log_level > SYSLOG_LEVEL_QUIET) { | 1510 | if (have_pty && options.log_level > SYSLOG_LEVEL_QUIET) { |
1576 | snprintf(buf, sizeof buf, "Connection to %.64s closed.\r\n", host); | 1511 | snprintf(buf, sizeof buf, |
1512 | "Connection to %.64s closed.\r\n", host); | ||
1577 | buffer_append(&stderr_buffer, buf, strlen(buf)); | 1513 | buffer_append(&stderr_buffer, buf, strlen(buf)); |
1578 | } | 1514 | } |
1579 | 1515 | ||
@@ -1586,7 +1522,6 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1586 | break; | 1522 | break; |
1587 | } | 1523 | } |
1588 | buffer_consume(&stdout_buffer, len); | 1524 | buffer_consume(&stdout_buffer, len); |
1589 | stdout_bytes += len; | ||
1590 | } | 1525 | } |
1591 | 1526 | ||
1592 | /* Output any buffered data for stderr. */ | 1527 | /* Output any buffered data for stderr. */ |
@@ -1598,7 +1533,6 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1598 | break; | 1533 | break; |
1599 | } | 1534 | } |
1600 | buffer_consume(&stderr_buffer, len); | 1535 | buffer_consume(&stderr_buffer, len); |
1601 | stderr_bytes += len; | ||
1602 | } | 1536 | } |
1603 | 1537 | ||
1604 | /* Clear and free any buffers. */ | 1538 | /* Clear and free any buffers. */ |
@@ -1609,13 +1543,13 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1609 | 1543 | ||
1610 | /* Report bytes transferred, and transfer rates. */ | 1544 | /* Report bytes transferred, and transfer rates. */ |
1611 | total_time = get_current_time() - start_time; | 1545 | total_time = get_current_time() - start_time; |
1612 | debug("Transferred: stdin %lu, stdout %lu, stderr %lu bytes in %.1f seconds", | 1546 | packet_get_state(MODE_IN, NULL, NULL, NULL, &ibytes); |
1613 | stdin_bytes, stdout_bytes, stderr_bytes, total_time); | 1547 | packet_get_state(MODE_OUT, NULL, NULL, NULL, &obytes); |
1548 | verbose("Transferred: sent %llu, received %llu bytes, in %.1f seconds", | ||
1549 | obytes, ibytes, total_time); | ||
1614 | if (total_time > 0) | 1550 | if (total_time > 0) |
1615 | debug("Bytes per second: stdin %.1f, stdout %.1f, stderr %.1f", | 1551 | verbose("Bytes per second: sent %.1f, received %.1f", |
1616 | stdin_bytes / total_time, stdout_bytes / total_time, | 1552 | obytes / total_time, ibytes / total_time); |
1617 | stderr_bytes / total_time); | ||
1618 | |||
1619 | /* Return the exit status of the program. */ | 1553 | /* Return the exit status of the program. */ |
1620 | debug("Exit status %d", exit_status); | 1554 | debug("Exit status %d", exit_status); |
1621 | return exit_status; | 1555 | return exit_status; |
@@ -1706,7 +1640,6 @@ client_request_forwarded_tcpip(const char *request_type, int rchan) | |||
1706 | Channel *c = NULL; | 1640 | Channel *c = NULL; |
1707 | char *listen_address, *originator_address; | 1641 | char *listen_address, *originator_address; |
1708 | int listen_port, originator_port; | 1642 | int listen_port, originator_port; |
1709 | int sock; | ||
1710 | 1643 | ||
1711 | /* Get rest of the packet */ | 1644 | /* Get rest of the packet */ |
1712 | listen_address = packet_get_string(NULL); | 1645 | listen_address = packet_get_string(NULL); |
@@ -1715,19 +1648,13 @@ client_request_forwarded_tcpip(const char *request_type, int rchan) | |||
1715 | originator_port = packet_get_int(); | 1648 | originator_port = packet_get_int(); |
1716 | packet_check_eom(); | 1649 | packet_check_eom(); |
1717 | 1650 | ||
1718 | debug("client_request_forwarded_tcpip: listen %s port %d, originator %s port %d", | 1651 | debug("client_request_forwarded_tcpip: listen %s port %d, " |
1719 | listen_address, listen_port, originator_address, originator_port); | 1652 | "originator %s port %d", listen_address, listen_port, |
1653 | originator_address, originator_port); | ||
1654 | |||
1655 | c = channel_connect_by_listen_address(listen_port, | ||
1656 | "forwarded-tcpip", originator_address); | ||
1720 | 1657 | ||
1721 | sock = channel_connect_by_listen_address(listen_port); | ||
1722 | if (sock < 0) { | ||
1723 | xfree(originator_address); | ||
1724 | xfree(listen_address); | ||
1725 | return NULL; | ||
1726 | } | ||
1727 | c = channel_new("forwarded-tcpip", | ||
1728 | SSH_CHANNEL_CONNECTING, sock, sock, -1, | ||
1729 | CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, | ||
1730 | originator_address, 1); | ||
1731 | xfree(originator_address); | 1658 | xfree(originator_address); |
1732 | xfree(listen_address); | 1659 | xfree(listen_address); |
1733 | return c; | 1660 | return c; |
@@ -1743,7 +1670,8 @@ client_request_x11(const char *request_type, int rchan) | |||
1743 | 1670 | ||
1744 | if (!options.forward_x11) { | 1671 | if (!options.forward_x11) { |
1745 | error("Warning: ssh server tried X11 forwarding."); | 1672 | error("Warning: ssh server tried X11 forwarding."); |
1746 | error("Warning: this is probably a break-in attempt by a malicious server."); | 1673 | error("Warning: this is probably a break-in attempt by a " |
1674 | "malicious server."); | ||
1747 | return NULL; | 1675 | return NULL; |
1748 | } | 1676 | } |
1749 | originator = packet_get_string(NULL); | 1677 | originator = packet_get_string(NULL); |
@@ -1776,7 +1704,8 @@ client_request_agent(const char *request_type, int rchan) | |||
1776 | 1704 | ||
1777 | if (!options.forward_agent) { | 1705 | if (!options.forward_agent) { |
1778 | error("Warning: ssh server tried agent forwarding."); | 1706 | error("Warning: ssh server tried agent forwarding."); |
1779 | error("Warning: this is probably a break-in attempt by a malicious server."); | 1707 | error("Warning: this is probably a break-in attempt by a " |
1708 | "malicious server."); | ||
1780 | return NULL; | 1709 | return NULL; |
1781 | } | 1710 | } |
1782 | sock = ssh_get_authentication_socket(); | 1711 | sock = ssh_get_authentication_socket(); |
@@ -1819,7 +1748,7 @@ client_request_tun_fwd(int tun_mode, int local_tun, int remote_tun) | |||
1819 | #if defined(SSH_TUN_FILTER) | 1748 | #if defined(SSH_TUN_FILTER) |
1820 | if (options.tun_open == SSH_TUNMODE_POINTOPOINT) | 1749 | if (options.tun_open == SSH_TUNMODE_POINTOPOINT) |
1821 | channel_register_filter(c->self, sys_tun_infilter, | 1750 | channel_register_filter(c->self, sys_tun_infilter, |
1822 | sys_tun_outfilter); | 1751 | sys_tun_outfilter, NULL, NULL); |
1823 | #endif | 1752 | #endif |
1824 | 1753 | ||
1825 | packet_start(SSH2_MSG_CHANNEL_OPEN); | 1754 | packet_start(SSH2_MSG_CHANNEL_OPEN); |
@@ -1902,7 +1831,11 @@ client_input_channel_req(int type, u_int32_t seq, void *ctxt) | |||
1902 | if (id == -1) { | 1831 | if (id == -1) { |
1903 | error("client_input_channel_req: request for channel -1"); | 1832 | error("client_input_channel_req: request for channel -1"); |
1904 | } else if ((c = channel_lookup(id)) == NULL) { | 1833 | } else if ((c = channel_lookup(id)) == NULL) { |
1905 | error("client_input_channel_req: channel %d: unknown channel", id); | 1834 | error("client_input_channel_req: channel %d: " |
1835 | "unknown channel", id); | ||
1836 | } else if (strcmp(rtype, "eow@openssh.com") == 0) { | ||
1837 | packet_check_eom(); | ||
1838 | chan_rcvd_eow(c); | ||
1906 | } else if (strcmp(rtype, "exit-status") == 0) { | 1839 | } else if (strcmp(rtype, "exit-status") == 0) { |
1907 | exitval = packet_get_int(); | 1840 | exitval = packet_get_int(); |
1908 | if (id == session_ident) { | 1841 | if (id == session_ident) { |
@@ -1947,8 +1880,7 @@ client_input_global_request(int type, u_int32_t seq, void *ctxt) | |||
1947 | 1880 | ||
1948 | void | 1881 | void |
1949 | client_session2_setup(int id, int want_tty, int want_subsystem, | 1882 | client_session2_setup(int id, int want_tty, int want_subsystem, |
1950 | const char *term, struct termios *tiop, int in_fd, Buffer *cmd, char **env, | 1883 | const char *term, struct termios *tiop, int in_fd, Buffer *cmd, char **env) |
1951 | dispatch_fn *subsys_repl) | ||
1952 | { | 1884 | { |
1953 | int len; | 1885 | int len; |
1954 | Channel *c = NULL; | 1886 | Channel *c = NULL; |
@@ -1960,20 +1892,21 @@ client_session2_setup(int id, int want_tty, int want_subsystem, | |||
1960 | 1892 | ||
1961 | if (want_tty) { | 1893 | if (want_tty) { |
1962 | struct winsize ws; | 1894 | struct winsize ws; |
1963 | struct termios tio; | ||
1964 | 1895 | ||
1965 | /* Store window size in the packet. */ | 1896 | /* Store window size in the packet. */ |
1966 | if (ioctl(in_fd, TIOCGWINSZ, &ws) < 0) | 1897 | if (ioctl(in_fd, TIOCGWINSZ, &ws) < 0) |
1967 | memset(&ws, 0, sizeof(ws)); | 1898 | memset(&ws, 0, sizeof(ws)); |
1968 | 1899 | ||
1969 | channel_request_start(id, "pty-req", 0); | 1900 | channel_request_start(id, "pty-req", 1); |
1901 | client_expect_confirm(id, "PTY allocation", 0); | ||
1970 | packet_put_cstring(term != NULL ? term : ""); | 1902 | packet_put_cstring(term != NULL ? term : ""); |
1971 | packet_put_int((u_int)ws.ws_col); | 1903 | packet_put_int((u_int)ws.ws_col); |
1972 | packet_put_int((u_int)ws.ws_row); | 1904 | packet_put_int((u_int)ws.ws_row); |
1973 | packet_put_int((u_int)ws.ws_xpixel); | 1905 | packet_put_int((u_int)ws.ws_xpixel); |
1974 | packet_put_int((u_int)ws.ws_ypixel); | 1906 | packet_put_int((u_int)ws.ws_ypixel); |
1975 | tio = get_saved_tio(); | 1907 | if (tiop == NULL) |
1976 | tty_make_modes(-1, tiop != NULL ? tiop : &tio); | 1908 | tiop = get_saved_tio(); |
1909 | tty_make_modes(-1, tiop); | ||
1977 | packet_send(); | 1910 | packet_send(); |
1978 | /* XXX wait for reply */ | 1911 | /* XXX wait for reply */ |
1979 | c->client_tty = 1; | 1912 | c->client_tty = 1; |
@@ -2021,22 +1954,21 @@ client_session2_setup(int id, int want_tty, int want_subsystem, | |||
2021 | if (len > 900) | 1954 | if (len > 900) |
2022 | len = 900; | 1955 | len = 900; |
2023 | if (want_subsystem) { | 1956 | if (want_subsystem) { |
2024 | debug("Sending subsystem: %.*s", len, (u_char*)buffer_ptr(cmd)); | 1957 | debug("Sending subsystem: %.*s", |
2025 | channel_request_start(id, "subsystem", subsys_repl != NULL); | 1958 | len, (u_char*)buffer_ptr(cmd)); |
2026 | if (subsys_repl != NULL) { | 1959 | channel_request_start(id, "subsystem", 1); |
2027 | /* register callback for reply */ | 1960 | client_expect_confirm(id, "subsystem", 1); |
2028 | /* XXX we assume that client_loop has already been called */ | ||
2029 | dispatch_set(SSH2_MSG_CHANNEL_FAILURE, subsys_repl); | ||
2030 | dispatch_set(SSH2_MSG_CHANNEL_SUCCESS, subsys_repl); | ||
2031 | } | ||
2032 | } else { | 1961 | } else { |
2033 | debug("Sending command: %.*s", len, (u_char*)buffer_ptr(cmd)); | 1962 | debug("Sending command: %.*s", |
2034 | channel_request_start(id, "exec", 0); | 1963 | len, (u_char*)buffer_ptr(cmd)); |
1964 | channel_request_start(id, "exec", 1); | ||
1965 | client_expect_confirm(id, "exec", 1); | ||
2035 | } | 1966 | } |
2036 | packet_put_string(buffer_ptr(cmd), buffer_len(cmd)); | 1967 | packet_put_string(buffer_ptr(cmd), buffer_len(cmd)); |
2037 | packet_send(); | 1968 | packet_send(); |
2038 | } else { | 1969 | } else { |
2039 | channel_request_start(id, "shell", 0); | 1970 | channel_request_start(id, "shell", 1); |
1971 | client_expect_confirm(id, "shell", 1); | ||
2040 | packet_send(); | 1972 | packet_send(); |
2041 | } | 1973 | } |
2042 | } | 1974 | } |
@@ -2055,6 +1987,8 @@ client_init_dispatch_20(void) | |||
2055 | dispatch_set(SSH2_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure); | 1987 | dispatch_set(SSH2_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure); |
2056 | dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &client_input_channel_req); | 1988 | dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &client_input_channel_req); |
2057 | dispatch_set(SSH2_MSG_CHANNEL_WINDOW_ADJUST, &channel_input_window_adjust); | 1989 | dispatch_set(SSH2_MSG_CHANNEL_WINDOW_ADJUST, &channel_input_window_adjust); |
1990 | dispatch_set(SSH2_MSG_CHANNEL_SUCCESS, &channel_input_status_confirm); | ||
1991 | dispatch_set(SSH2_MSG_CHANNEL_FAILURE, &channel_input_status_confirm); | ||
2058 | dispatch_set(SSH2_MSG_GLOBAL_REQUEST, &client_input_global_request); | 1992 | dispatch_set(SSH2_MSG_GLOBAL_REQUEST, &client_input_global_request); |
2059 | 1993 | ||
2060 | /* rekeying */ | 1994 | /* rekeying */ |
@@ -2064,6 +1998,7 @@ client_init_dispatch_20(void) | |||
2064 | dispatch_set(SSH2_MSG_REQUEST_FAILURE, &client_global_request_reply); | 1998 | dispatch_set(SSH2_MSG_REQUEST_FAILURE, &client_global_request_reply); |
2065 | dispatch_set(SSH2_MSG_REQUEST_SUCCESS, &client_global_request_reply); | 1999 | dispatch_set(SSH2_MSG_REQUEST_SUCCESS, &client_global_request_reply); |
2066 | } | 2000 | } |
2001 | |||
2067 | static void | 2002 | static void |
2068 | client_init_dispatch_13(void) | 2003 | client_init_dispatch_13(void) |
2069 | { | 2004 | { |
@@ -2083,6 +2018,7 @@ client_init_dispatch_13(void) | |||
2083 | dispatch_set(SSH_SMSG_X11_OPEN, options.forward_x11 ? | 2018 | dispatch_set(SSH_SMSG_X11_OPEN, options.forward_x11 ? |
2084 | &x11_input_open : &deny_input_open); | 2019 | &x11_input_open : &deny_input_open); |
2085 | } | 2020 | } |
2021 | |||
2086 | static void | 2022 | static void |
2087 | client_init_dispatch_15(void) | 2023 | client_init_dispatch_15(void) |
2088 | { | 2024 | { |
@@ -2090,6 +2026,7 @@ client_init_dispatch_15(void) | |||
2090 | dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_ieof); | 2026 | dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_ieof); |
2091 | dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, & channel_input_oclose); | 2027 | dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, & channel_input_oclose); |
2092 | } | 2028 | } |
2029 | |||
2093 | static void | 2030 | static void |
2094 | client_init_dispatch(void) | 2031 | client_init_dispatch(void) |
2095 | { | 2032 | { |
@@ -2107,7 +2044,7 @@ cleanup_exit(int i) | |||
2107 | { | 2044 | { |
2108 | leave_raw_mode(); | 2045 | leave_raw_mode(); |
2109 | leave_non_blocking(); | 2046 | leave_non_blocking(); |
2110 | if (options.control_path != NULL && control_fd != -1) | 2047 | if (options.control_path != NULL && muxserver_sock != -1) |
2111 | unlink(options.control_path); | 2048 | unlink(options.control_path); |
2112 | _exit(i); | 2049 | _exit(i); |
2113 | } | 2050 | } |