summaryrefslogtreecommitdiff
path: root/clientloop.c
diff options
context:
space:
mode:
authorColin Watson <cjwatson@debian.org>2008-07-22 19:45:18 +0000
committerColin Watson <cjwatson@debian.org>2008-07-22 19:45:18 +0000
commit137d76ba65883aa8143af1fcad83b57e7badef0c (patch)
treef426e804bb5248ceafedfab7bb78ae6e6752942c /clientloop.c
parentdac7d049dad31f5f84d421d4eb628a7e13f977d7 (diff)
parentef94e5613d37bcbf880f21ee6094e4b1c7683a4c (diff)
* New upstream release (closes: #474301). Important changes not previously
backported to 4.7p1: - 4.9/4.9p1 (http://www.openssh.com/txt/release-4.9): + Added chroot(2) support for sshd(8), controlled by a new option "ChrootDirectory" (closes: #139047, LP: #24777). + Linked sftp-server(8) into sshd(8). The internal sftp server is used when the command "internal-sftp" is specified in a Subsystem or ForceCommand declaration. When used with ChrootDirectory, the internal sftp server requires no special configuration of files inside the chroot environment. + Added a protocol extension method "posix-rename@openssh.com" for sftp-server(8) to perform POSIX atomic rename() operations; sftp(1) prefers this if available (closes: #308561). + Removed the fixed limit of 100 file handles in sftp-server(8). + ssh(8) will now skip generation of SSH protocol 1 ephemeral server keys when in inetd mode and protocol 2 connections are negotiated. This speeds up protocol 2 connections to inetd-mode servers that also allow Protocol 1. + Accept the PermitRootLogin directive in a sshd_config(5) Match block. Allows for, e.g. permitting root only from the local network. + Reworked sftp(1) argument splitting and escaping to be more internally consistent (i.e. between sftp commands) and more consistent with sh(1). Please note that this will change the interpretation of some quoted strings, especially those with embedded backslash escape sequences. + Support "Banner=none" in sshd_config(5) to disable sending of a pre-login banner (e.g. in a Match block). + ssh(1) ProxyCommands are now executed with $SHELL rather than /bin/sh. + ssh(1)'s ConnectTimeout option is now applied to both the TCP connection and the SSH banner exchange (previously it just covered the TCP connection). This allows callers of ssh(1) to better detect and deal with stuck servers that accept a TCP connection but don't progress the protocol, and also makes ConnectTimeout useful for connections via a ProxyCommand. + scp(1) incorrectly reported "stalled" on slow copies (closes: #140828). + scp(1) date underflow for timestamps before epoch. + ssh(1) used the obsolete SIG DNS RRtype for host keys in DNS, instead of the current standard RRSIG. + Correctly drain ACKs when a sftp(1) upload write fails midway, avoids a fatal() exit from what should be a recoverable condition. + Fixed ssh-keygen(1) selective host key hashing (i.e. "ssh-keygen -HF hostname") to not include any IP address in the data to be hashed. + Make ssh(1) skip listening on the IPv6 wildcard address when a binding address of 0.0.0.0 is used against an old SSH server that does not support the RFC4254 syntax for wildcard bind addresses. + Enable IPV6_V6ONLY socket option on sshd(8) listen socket, as is already done for X11/TCP forwarding sockets (closes: #439661). + Fix FD leak that could hang a ssh(1) connection multiplexing master. + Make ssh(1) -q option documentation consistent with reality. + Fixed sshd(8) PAM support not calling pam_session_close(), or failing to call it with root privileges (closes: #372680). + Fix activation of OpenSSL engine support when requested in configure (LP: #119295). - 5.1/5.1p1 (http://www.openssh.com/txt/release-5.1): + Introduce experimental SSH Fingerprint ASCII Visualisation to ssh(1) and ssh-keygen(1). Visual fingerprint display is controlled by a new ssh_config(5) option "VisualHostKey". The intent is to render SSH host keys in a visual form that is amenable to easy recall and rejection of changed host keys. + sshd_config(5) now supports CIDR address/masklen matching in "Match address" blocks, with a fallback to classic wildcard matching. + sshd(8) now supports CIDR matching in ~/.ssh/authorized_keys from="..." restrictions, also with a fallback to classic wildcard matching. + Added an extended test mode (-T) to sshd(8) to request that it write its effective configuration to stdout and exit. Extended test mode also supports the specification of connection parameters (username, source address and hostname) to test the application of sshd_config(5) Match rules. + ssh(1) now prints the number of bytes transferred and the overall connection throughput for SSH protocol 2 sessions when in verbose mode (previously these statistics were displayed for protocol 1 connections only). + sftp-server(8) now supports extension methods statvfs@openssh.com and fstatvfs@openssh.com that implement statvfs(2)-like operations. + sftp(1) now has a "df" command to the sftp client that uses the statvfs@openssh.com to produce a df(1)-like display of filesystem space and inode utilisation (requires statvfs@openssh.com support on the server). + Added a MaxSessions option to sshd_config(5) to allow control of the number of multiplexed sessions supported over a single TCP connection. This allows increasing the number of allowed sessions above the previous default of 10, disabling connection multiplexing (MaxSessions=1) or disallowing login/shell/subsystem sessions entirely (MaxSessions=0). + Added a no-more-sessions@openssh.com global request extension that is sent from ssh(1) to sshd(8) when the client knows that it will never request another session (i.e. when session multiplexing is disabled). This allows a server to disallow further session requests and terminate the session in cases where the client has been hijacked. + ssh-keygen(1) now supports the use of the -l option in combination with -F to search for a host in ~/.ssh/known_hosts and display its fingerprint. + ssh-keyscan(1) now defaults to "rsa" (protocol 2) keys, instead of "rsa1". + Added an AllowAgentForwarding option to sshd_config(8) to control whether authentication agent forwarding is permitted. Note that this is a loose control, as a client may install their own unofficial forwarder. + ssh(1) and sshd(8): avoid unnecessary malloc/copy/free when receiving network data, resulting in a ~10% speedup. + ssh(1) and sshd(8) will now try additional addresses when connecting to a port forward destination whose DNS name resolves to more than one address. The previous behaviour was to try the only first address and give up if that failed. + ssh(1) and sshd(8) now support signalling that channels are half-closed for writing, through a channel protocol extension notification "eow@openssh.com". This allows propagation of closed file descriptors, so that commands such as "ssh -2 localhost od /bin/ls | true" do not send unnecessary data over the wire. + sshd(8): increased the default size of ssh protocol 1 ephemeral keys from 768 to 1024 bits. + When ssh(1) has been requested to fork after authentication ("ssh -f") with ExitOnForwardFailure enabled, delay the fork until after replies for any -R forwards have been seen. Allows for robust detection of -R forward failure when using -f. + "Match group" blocks in sshd_config(5) now support negation of groups. E.g. "Match group staff,!guests". + sftp(1) and sftp-server(8) now allow chmod-like operations to set set[ug]id/sticky bits. + The MaxAuthTries option is now permitted in sshd_config(5) match blocks. + Multiplexed ssh(1) sessions now support a subset of the ~ escapes that are available to a primary connection. + ssh(1) connection multiplexing will now fall back to creating a new connection in most error cases (closes: #352830). + Make ssh(1) deal more gracefully with channel requests that fail. Previously it would optimistically assume that requests would always succeed, which could cause hangs if they did not (e.g. when the server runs out of file descriptors). + ssh(1) now reports multiplexing errors via the multiplex slave's stderr where possible (subject to LogLevel in the mux master). + Prevent sshd(8) from erroneously applying public key restrictions leaned from ~/.ssh/authorized_keys to other authentication methods when public key authentication subsequently fails (LP: #161047). + Fixed an UMAC alignment problem that manifested on Itanium platforms.
Diffstat (limited to 'clientloop.c')
-rw-r--r--clientloop.c753
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;
120extern int no_shell_flag; 121extern int no_shell_flag;
121 122
122/* Control socket */ 123/* Control socket */
123extern int control_fd; 124extern 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. */
145static volatile sig_atomic_t quit_pending; /* Set non-zero to quit the loop. */ 146static volatile sig_atomic_t quit_pending; /* Set non-zero to quit the loop. */
146static int escape_char; /* Escape character. */ 147static int escape_char1; /* Escape character. (proto1 only) */
147static int escape_pending; /* Last character was the escape character */ 148static int escape_pending1; /* Last character was an escape (proto1 only) */
148static int last_was_cr; /* Last character was a newline. */ 149static int last_was_cr; /* Last character was a newline. */
149static int exit_status; /* Used to store the exit status of the command. */ 150static int exit_status; /* Used to store the command exit status. */
150static int stdin_eof; /* EOF has been encountered on standard error. */ 151static int stdin_eof; /* EOF has been encountered on stderr. */
151static Buffer stdin_buffer; /* Buffer for stdin data. */ 152static Buffer stdin_buffer; /* Buffer for stdin data. */
152static Buffer stdout_buffer; /* Buffer for stdout data. */ 153static Buffer stdout_buffer; /* Buffer for stdout data. */
153static Buffer stderr_buffer; /* Buffer for stderr data. */ 154static Buffer stderr_buffer; /* Buffer for stderr data. */
154static u_long stdin_bytes, stdout_bytes, stderr_bytes;
155static u_int buffer_high;/* Soft max buffer size. */ 155static u_int buffer_high;/* Soft max buffer size. */
156static int connection_in; /* Connection to server (input). */ 156static int connection_in; /* Connection to server (input). */
157static int connection_out; /* Connection to server (output). */ 157static int connection_out; /* Connection to server (output). */
158static int need_rekeying; /* Set to non-zero if rekeying is requested. */ 158static int need_rekeying; /* Set to non-zero if rekeying is requested. */
159static int session_closed = 0; /* In SSH2: login session closed. */ 159static int session_closed = 0; /* In SSH2: login session closed. */
160static int server_alive_timeouts = 0;
161 160
162static void client_init_dispatch(void); 161static void client_init_dispatch(void);
163int session_ident = -1; 162int session_ident = -1;
164 163
165struct confirm_ctx { 164/* Track escape per proto2 channel */
166 int want_tty; 165struct 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 */
171struct channel_reply_ctx {
172 const char *request_type;
173 int id, do_close;
174};
175
176/* Global request success/failure callbacks */
177struct global_confirm {
178 TAILQ_ENTRY(global_confirm) entry;
179 global_confirm_cb *cb;
180 void *ctx;
181 int ref_count;
182};
183TAILQ_HEAD(global_confirms, global_confirm);
184static struct global_confirms global_confirms =
185 TAILQ_HEAD_INITIALIZER(global_confirms);
186
176/*XXX*/ 187/*XXX*/
177extern Kex *xxx_kex; 188extern 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)
467static void 480static void
468client_global_request_reply(int type, u_int32_t seq, void *ctxt) 481client_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
474static void 498static void
475server_alive_check(void) 499server_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
652static void 689static void
653client_subsystem_reply(int type, u_int32_t seq, void *ctxt) 690client_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
674static void 728static void
675client_extra_session2_setup(int id, void *arg) 729client_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
720static void 734static void
721client_process_control(fd_set *readset) 735client_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__, 746void
874 cctx->want_tty, cctx->want_subsys, cmd); 747client_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
938static void 767static 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 */
1050static int 888static int
1051process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len) 889process_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\
1167Supported escape sequences:\r\n\ 1041Supported 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\
1058Supported 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)
1341static void 1247static void
1342client_process_buffered_input_packets(void) 1248client_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
1349static int 1256/* Helper: allocate a new escape_filter_ctx and fill in its escape char */
1350simple_escape_filter(Channel *c, char *buf, int len) 1257void *
1258client_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 */
1269void
1270client_filter_cleanup(int cid, void *ctx)
1271{
1272 xfree(ctx);
1273}
1274
1275int
1276client_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
1356static void 1285static 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
1948void 1881void
1949client_session2_setup(int id, int want_tty, int want_subsystem, 1882client_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
2067static void 2002static void
2068client_init_dispatch_13(void) 2003client_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
2086static void 2022static void
2087client_init_dispatch_15(void) 2023client_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
2093static void 2030static void
2094client_init_dispatch(void) 2031client_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}