summaryrefslogtreecommitdiff
path: root/ssh.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 /ssh.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 'ssh.c')
-rw-r--r--ssh.c541
1 files changed, 170 insertions, 371 deletions
diff --git a/ssh.c b/ssh.c
index 85043a8c0..e2e2ef498 100644
--- a/ssh.c
+++ b/ssh.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh.c,v 1.301 2007/08/07 07:32:53 djm Exp $ */ 1/* $OpenBSD: ssh.c,v 1.318 2008/07/02 13:47:39 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
@@ -49,7 +49,6 @@
49#include <sys/resource.h> 49#include <sys/resource.h>
50#include <sys/ioctl.h> 50#include <sys/ioctl.h>
51#include <sys/socket.h> 51#include <sys/socket.h>
52#include <sys/un.h>
53 52
54#include <ctype.h> 53#include <ctype.h>
55#include <errno.h> 54#include <errno.h>
@@ -72,6 +71,8 @@
72 71
73#include <openssl/evp.h> 72#include <openssl/evp.h>
74#include <openssl/err.h> 73#include <openssl/err.h>
74#include "openbsd-compat/openssl-compat.h"
75#include "openbsd-compat/sys-queue.h"
75 76
76#include "xmalloc.h" 77#include "xmalloc.h"
77#include "ssh.h" 78#include "ssh.h"
@@ -97,7 +98,6 @@
97#include "sshpty.h" 98#include "sshpty.h"
98#include "match.h" 99#include "match.h"
99#include "msg.h" 100#include "msg.h"
100#include "monitor_fdpass.h"
101#include "uidswap.h" 101#include "uidswap.h"
102#include "version.h" 102#include "version.h"
103 103
@@ -107,7 +107,7 @@
107 107
108extern char *__progname; 108extern char *__progname;
109 109
110/* Flag indicating whether debug mode is on. This can be set on the command line. */ 110/* Flag indicating whether debug mode is on. May be set on the command line. */
111int debug_flag = 0; 111int debug_flag = 0;
112 112
113/* Flag indicating whether a tty should be allocated */ 113/* Flag indicating whether a tty should be allocated */
@@ -164,20 +164,14 @@ Buffer command;
164int subsystem_flag = 0; 164int subsystem_flag = 0;
165 165
166/* # of replies received for global requests */ 166/* # of replies received for global requests */
167static int client_global_request_id = 0; 167static int remote_forward_confirms_received = 0;
168 168
169/* pid of proxycommand child process */ 169/* pid of proxycommand child process */
170pid_t proxy_command_pid = 0; 170pid_t proxy_command_pid = 0;
171 171
172/* fd to control socket */ 172/* mux.c */
173int control_fd = -1; 173extern int muxserver_sock;
174 174extern u_int muxclient_command;
175/* Multiplexing control command */
176static u_int mux_command = 0;
177
178/* Only used in control client mode */
179volatile sig_atomic_t control_client_terminate = 0;
180u_int control_server_pid = 0;
181 175
182/* Prints a help message to the user. This function never returns. */ 176/* Prints a help message to the user. This function never returns. */
183 177
@@ -198,7 +192,10 @@ usage(void)
198static int ssh_session(void); 192static int ssh_session(void);
199static int ssh_session2(void); 193static int ssh_session2(void);
200static void load_public_identity_files(void); 194static void load_public_identity_files(void);
201static void control_client(const char *path); 195
196/* from muxclient.c */
197void muxclient(const char *);
198void muxserver_listen(void);
202 199
203/* 200/*
204 * Main program for the ssh client. 201 * Main program for the ssh client.
@@ -210,7 +207,7 @@ main(int ac, char **av)
210 char *p, *cp, *line, buf[256]; 207 char *p, *cp, *line, buf[256];
211 struct stat st; 208 struct stat st;
212 struct passwd *pw; 209 struct passwd *pw;
213 int dummy; 210 int dummy, timeout_ms;
214 extern int optind, optreset; 211 extern int optind, optreset;
215 extern char *optarg; 212 extern char *optarg;
216 struct servent *sp; 213 struct servent *sp;
@@ -264,15 +261,18 @@ main(int ac, char **av)
264 */ 261 */
265 umask(022); 262 umask(022);
266 263
267 /* Initialize option structure to indicate that no values have been set. */ 264 /*
265 * Initialize option structure to indicate that no values have been
266 * set.
267 */
268 initialize_options(&options); 268 initialize_options(&options);
269 269
270 /* Parse command-line arguments. */ 270 /* Parse command-line arguments. */
271 host = NULL; 271 host = NULL;
272 272
273 again: 273 again:
274 while ((opt = getopt(ac, av, 274 while ((opt = getopt(ac, av, "1246ab:c:e:fgi:kl:m:no:p:qstvx"
275 "1246ab:c:e:fgi:kl:m:no:p:qstvxACD:F:I:KL:MNO:PR:S:TVw:XY")) != -1) { 275 "ACD:F:I:KL:MNO:PR:S:TVw:XY")) != -1) {
276 switch (opt) { 276 switch (opt) {
277 case '1': 277 case '1':
278 options.protocol = SSH_PROTO_1; 278 options.protocol = SSH_PROTO_1;
@@ -308,9 +308,9 @@ main(int ac, char **av)
308 break; 308 break;
309 case 'O': 309 case 'O':
310 if (strcmp(optarg, "check") == 0) 310 if (strcmp(optarg, "check") == 0)
311 mux_command = SSHMUX_COMMAND_ALIVE_CHECK; 311 muxclient_command = SSHMUX_COMMAND_ALIVE_CHECK;
312 else if (strcmp(optarg, "exit") == 0) 312 else if (strcmp(optarg, "exit") == 0)
313 mux_command = SSHMUX_COMMAND_TERMINATE; 313 muxclient_command = SSHMUX_COMMAND_TERMINATE;
314 else 314 else
315 fatal("Invalid multiplex command."); 315 fatal("Invalid multiplex command.");
316 break; 316 break;
@@ -377,7 +377,8 @@ main(int ac, char **av)
377 options.tun_open = SSH_TUNMODE_DEFAULT; 377 options.tun_open = SSH_TUNMODE_DEFAULT;
378 options.tun_local = a2tun(optarg, &options.tun_remote); 378 options.tun_local = a2tun(optarg, &options.tun_remote);
379 if (options.tun_local == SSH_TUNID_ERR) { 379 if (options.tun_local == SSH_TUNID_ERR) {
380 fprintf(stderr, "Bad tun device '%s'\n", optarg); 380 fprintf(stderr,
381 "Bad tun device '%s'\n", optarg);
381 exit(255); 382 exit(255);
382 } 383 }
383 break; 384 break;
@@ -485,7 +486,8 @@ main(int ac, char **av)
485 } 486 }
486 if (cp != NULL) { 487 if (cp != NULL) {
487 fwd.listen_port = a2port(cp); 488 fwd.listen_port = a2port(cp);
488 fwd.listen_host = cleanhostname(fwd.listen_host); 489 fwd.listen_host =
490 cleanhostname(fwd.listen_host);
489 } else { 491 } else {
490 fwd.listen_port = a2port(fwd.listen_host); 492 fwd.listen_port = a2port(fwd.listen_host);
491 fwd.listen_host = NULL; 493 fwd.listen_host = NULL;
@@ -591,8 +593,10 @@ main(int ac, char **av)
591 } 593 }
592 594
593 /* Cannot fork to background if no command. */ 595 /* Cannot fork to background if no command. */
594 if (fork_after_authentication_flag && buffer_len(&command) == 0 && !no_shell_flag) 596 if (fork_after_authentication_flag && buffer_len(&command) == 0 &&
595 fatal("Cannot fork into background without a command to execute."); 597 !no_shell_flag)
598 fatal("Cannot fork into background without a command "
599 "to execute.");
596 600
597 /* Allocate a tty by default if no command specified. */ 601 /* Allocate a tty by default if no command specified. */
598 if (buffer_len(&command) == 0) 602 if (buffer_len(&command) == 0)
@@ -604,7 +608,8 @@ main(int ac, char **av)
604 /* Do not allocate a tty if stdin is not a tty. */ 608 /* Do not allocate a tty if stdin is not a tty. */
605 if ((!isatty(fileno(stdin)) || stdin_null_flag) && !force_tty_flag) { 609 if ((!isatty(fileno(stdin)) || stdin_null_flag) && !force_tty_flag) {
606 if (tty_flag && options.log_level > SYSLOG_LEVEL_QUIET) 610 if (tty_flag && options.log_level > SYSLOG_LEVEL_QUIET)
607 logit("Pseudo-terminal will not be allocated because stdin is not a terminal."); 611 logit("Pseudo-terminal will not be allocated because "
612 "stdin is not a terminal.");
608 tty_flag = 0; 613 tty_flag = 0;
609 } 614 }
610 615
@@ -612,7 +617,8 @@ main(int ac, char **av)
612 * Initialize "log" output. Since we are the client all output 617 * Initialize "log" output. Since we are the client all output
613 * actually goes to stderr. 618 * actually goes to stderr.
614 */ 619 */
615 log_init(av[0], options.log_level == -1 ? SYSLOG_LEVEL_INFO : options.log_level, 620 log_init(av[0],
621 options.log_level == -1 ? SYSLOG_LEVEL_INFO : options.log_level,
616 SYSLOG_FACILITY_USER, 1); 622 SYSLOG_FACILITY_USER, 1);
617 623
618 /* 624 /*
@@ -646,6 +652,28 @@ main(int ac, char **av)
646 if (options.user == NULL) 652 if (options.user == NULL)
647 options.user = xstrdup(pw->pw_name); 653 options.user = xstrdup(pw->pw_name);
648 654
655 /* Get default port if port has not been set. */
656 if (options.port == 0) {
657 sp = getservbyname(SSH_SERVICE_NAME, "tcp");
658 options.port = sp ? ntohs(sp->s_port) : SSH_DEFAULT_PORT;
659 }
660
661 if (options.local_command != NULL) {
662 char thishost[NI_MAXHOST];
663
664 if (gethostname(thishost, sizeof(thishost)) == -1)
665 fatal("gethostname: %s", strerror(errno));
666 snprintf(buf, sizeof(buf), "%d", options.port);
667 debug3("expanding LocalCommand: %s", options.local_command);
668 cp = options.local_command;
669 options.local_command = percent_expand(cp, "d", pw->pw_dir,
670 "h", options.hostname? options.hostname : host,
671 "l", thishost, "n", host, "r", options.user, "p", buf,
672 "u", pw->pw_name, (char *)NULL);
673 debug3("expanded LocalCommand: %s", options.local_command);
674 xfree(cp);
675 }
676
649 if (options.hostname != NULL) 677 if (options.hostname != NULL)
650 host = options.hostname; 678 host = options.hostname;
651 679
@@ -656,18 +684,16 @@ main(int ac, char **av)
656 *p = (char)tolower(*p); 684 *p = (char)tolower(*p);
657 } 685 }
658 686
659 /* Get default port if port has not been set. */
660 if (options.port == 0) {
661 sp = getservbyname(SSH_SERVICE_NAME, "tcp");
662 options.port = sp ? ntohs(sp->s_port) : SSH_DEFAULT_PORT;
663 }
664
665 if (options.proxy_command != NULL && 687 if (options.proxy_command != NULL &&
666 strcmp(options.proxy_command, "none") == 0) 688 strcmp(options.proxy_command, "none") == 0) {
689 xfree(options.proxy_command);
667 options.proxy_command = NULL; 690 options.proxy_command = NULL;
691 }
668 if (options.control_path != NULL && 692 if (options.control_path != NULL &&
669 strcmp(options.control_path, "none") == 0) 693 strcmp(options.control_path, "none") == 0) {
694 xfree(options.control_path);
670 options.control_path = NULL; 695 options.control_path = NULL;
696 }
671 697
672 if (options.control_path != NULL) { 698 if (options.control_path != NULL) {
673 char thishost[NI_MAXHOST]; 699 char thishost[NI_MAXHOST];
@@ -677,18 +703,22 @@ main(int ac, char **av)
677 snprintf(buf, sizeof(buf), "%d", options.port); 703 snprintf(buf, sizeof(buf), "%d", options.port);
678 cp = tilde_expand_filename(options.control_path, 704 cp = tilde_expand_filename(options.control_path,
679 original_real_uid); 705 original_real_uid);
706 xfree(options.control_path);
680 options.control_path = percent_expand(cp, "p", buf, "h", host, 707 options.control_path = percent_expand(cp, "p", buf, "h", host,
681 "r", options.user, "l", thishost, (char *)NULL); 708 "r", options.user, "l", thishost, (char *)NULL);
682 xfree(cp); 709 xfree(cp);
683 } 710 }
684 if (mux_command != 0 && options.control_path == NULL) 711 if (muxclient_command != 0 && options.control_path == NULL)
685 fatal("No ControlPath specified for \"-O\" command"); 712 fatal("No ControlPath specified for \"-O\" command");
686 if (options.control_path != NULL) 713 if (options.control_path != NULL)
687 control_client(options.control_path); 714 muxclient(options.control_path);
715
716 timeout_ms = options.connection_timeout * 1000;
688 717
689 /* Open a connection to the remote host. */ 718 /* Open a connection to the remote host. */
690 if (ssh_connect(host, &hostaddr, options.port, 719 if (ssh_connect(host, &hostaddr, options.port,
691 options.address_family, options.connection_attempts, 720 options.address_family, options.connection_attempts, &timeout_ms,
721 options.tcp_keep_alive,
692#ifdef HAVE_CYGWIN 722#ifdef HAVE_CYGWIN
693 options.use_privileged_port, 723 options.use_privileged_port,
694#else 724#else
@@ -697,6 +727,9 @@ main(int ac, char **av)
697 options.proxy_command) != 0) 727 options.proxy_command) != 0)
698 exit(255); 728 exit(255);
699 729
730 if (timeout_ms > 0)
731 debug3("timeout: %d ms remain after connect", timeout_ms);
732
700 /* 733 /*
701 * If we successfully made the connection, load the host private key 734 * If we successfully made the connection, load the host private key
702 * in case we will need it later for combined rsa-rhosts 735 * in case we will need it later for combined rsa-rhosts
@@ -750,7 +783,8 @@ main(int ac, char **av)
750 * Now that we are back to our own permissions, create ~/.ssh 783 * Now that we are back to our own permissions, create ~/.ssh
751 * directory if it doesn't already exist. 784 * directory if it doesn't already exist.
752 */ 785 */
753 snprintf(buf, sizeof buf, "%.100s%s%.100s", pw->pw_dir, strcmp(pw->pw_dir, "/") ? "/" : "", _PATH_SSH_USER_DIR); 786 snprintf(buf, sizeof buf, "%.100s%s%.100s", pw->pw_dir,
787 strcmp(pw->pw_dir, "/") ? "/" : "", _PATH_SSH_USER_DIR);
754 if (stat(buf, &st) < 0) 788 if (stat(buf, &st) < 0)
755 if (mkdir(buf, 0700) < 0) 789 if (mkdir(buf, 0700) < 0)
756 error("Could not create directory '%.200s'.", buf); 790 error("Could not create directory '%.200s'.", buf);
@@ -771,8 +805,9 @@ main(int ac, char **av)
771 805
772 signal(SIGPIPE, SIG_IGN); /* ignore SIGPIPE early */ 806 signal(SIGPIPE, SIG_IGN); /* ignore SIGPIPE early */
773 807
774 /* Log into the remote system. This never returns if the login fails. */ 808 /* Log into the remote system. Never returns if the login fails. */
775 ssh_login(&sensitive_data, host, (struct sockaddr *)&hostaddr, pw); 809 ssh_login(&sensitive_data, host, (struct sockaddr *)&hostaddr,
810 pw, timeout_ms);
776 811
777 /* We no longer need the private host keys. Clear them now. */ 812 /* We no longer need the private host keys. Clear them now. */
778 if (sensitive_data.nkeys != 0) { 813 if (sensitive_data.nkeys != 0) {
@@ -800,7 +835,7 @@ main(int ac, char **av)
800 exit_status = compat20 ? ssh_session2() : ssh_session(); 835 exit_status = compat20 ? ssh_session2() : ssh_session();
801 packet_close(); 836 packet_close();
802 837
803 if (options.control_path != NULL && control_fd != -1) 838 if (options.control_path != NULL && muxserver_sock != -1)
804 unlink(options.control_path); 839 unlink(options.control_path);
805 840
806 /* 841 /*
@@ -813,6 +848,34 @@ main(int ac, char **av)
813 return exit_status; 848 return exit_status;
814} 849}
815 850
851/* Callback for remote forward global requests */
852static void
853ssh_confirm_remote_forward(int type, u_int32_t seq, void *ctxt)
854{
855 Forward *rfwd = (Forward *)ctxt;
856
857 debug("remote forward %s for: listen %d, connect %s:%d",
858 type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure",
859 rfwd->listen_port, rfwd->connect_host, rfwd->connect_port);
860 if (type == SSH2_MSG_REQUEST_FAILURE) {
861 if (options.exit_on_forward_failure)
862 fatal("Error: remote port forwarding failed for "
863 "listen port %d", rfwd->listen_port);
864 else
865 logit("Warning: remote port forwarding failed for "
866 "listen port %d", rfwd->listen_port);
867 }
868 if (++remote_forward_confirms_received == options.num_remote_forwards) {
869 debug("All remote forwarding requests processed");
870 if (fork_after_authentication_flag) {
871 fork_after_authentication_flag = 0;
872 if (daemon(1, 1) < 0)
873 fatal("daemon() failed: %.200s",
874 strerror(errno));
875 }
876 }
877}
878
816static void 879static void
817ssh_init_forwarding(void) 880ssh_init_forwarding(void)
818{ 881{
@@ -861,6 +924,8 @@ ssh_init_forwarding(void)
861 logit("Warning: Could not request remote " 924 logit("Warning: Could not request remote "
862 "forwarding."); 925 "forwarding.");
863 } 926 }
927 client_register_global_confirm(ssh_confirm_remote_forward,
928 &options.remote_forwards[i]);
864 } 929 }
865 930
866 /* Initiate tunnel forwarding. */ 931 /* Initiate tunnel forwarding. */
@@ -897,10 +962,13 @@ ssh_session(void)
897 962
898 /* Enable compression if requested. */ 963 /* Enable compression if requested. */
899 if (options.compression) { 964 if (options.compression) {
900 debug("Requesting compression at level %d.", options.compression_level); 965 debug("Requesting compression at level %d.",
966 options.compression_level);
901 967
902 if (options.compression_level < 1 || options.compression_level > 9) 968 if (options.compression_level < 1 ||
903 fatal("Compression level must be from 1 (fast) to 9 (slow, best)."); 969 options.compression_level > 9)
970 fatal("Compression level must be from 1 (fast) to "
971 "9 (slow, best).");
904 972
905 /* Send the request. */ 973 /* Send the request. */
906 packet_start(SSH_CMSG_REQUEST_COMPRESSION); 974 packet_start(SSH_CMSG_REQUEST_COMPRESSION);
@@ -913,7 +981,8 @@ ssh_session(void)
913 else if (type == SSH_SMSG_FAILURE) 981 else if (type == SSH_SMSG_FAILURE)
914 logit("Warning: Remote host refused compression."); 982 logit("Warning: Remote host refused compression.");
915 else 983 else
916 packet_disconnect("Protocol error waiting for compression response."); 984 packet_disconnect("Protocol error waiting for "
985 "compression response.");
917 } 986 }
918 /* Allocate a pseudo tty if appropriate. */ 987 /* Allocate a pseudo tty if appropriate. */
919 if (tty_flag) { 988 if (tty_flag) {
@@ -950,9 +1019,11 @@ ssh_session(void)
950 interactive = 1; 1019 interactive = 1;
951 have_tty = 1; 1020 have_tty = 1;
952 } else if (type == SSH_SMSG_FAILURE) 1021 } else if (type == SSH_SMSG_FAILURE)
953 logit("Warning: Remote host failed or refused to allocate a pseudo tty."); 1022 logit("Warning: Remote host failed or refused to "
1023 "allocate a pseudo tty.");
954 else 1024 else
955 packet_disconnect("Protocol error waiting for pty request response."); 1025 packet_disconnect("Protocol error waiting for pty "
1026 "request response.");
956 } 1027 }
957 /* Request X11 forwarding if enabled and DISPLAY is set. */ 1028 /* Request X11 forwarding if enabled and DISPLAY is set. */
958 display = getenv("DISPLAY"); 1029 display = getenv("DISPLAY");
@@ -962,7 +1033,8 @@ ssh_session(void)
962 client_x11_get_proto(display, options.xauth_location, 1033 client_x11_get_proto(display, options.xauth_location,
963 options.forward_x11_trusted, &proto, &data); 1034 options.forward_x11_trusted, &proto, &data);
964 /* Request forwarding with authentication spoofing. */ 1035 /* Request forwarding with authentication spoofing. */
965 debug("Requesting X11 forwarding with authentication spoofing."); 1036 debug("Requesting X11 forwarding with authentication "
1037 "spoofing.");
966 x11_request_forwarding_with_spoofing(0, display, proto, data); 1038 x11_request_forwarding_with_spoofing(0, display, proto, data);
967 1039
968 /* Read response from the server. */ 1040 /* Read response from the server. */
@@ -972,7 +1044,8 @@ ssh_session(void)
972 } else if (type == SSH_SMSG_FAILURE) { 1044 } else if (type == SSH_SMSG_FAILURE) {
973 logit("Warning: Remote host denied X11 forwarding."); 1045 logit("Warning: Remote host denied X11 forwarding.");
974 } else { 1046 } else {
975 packet_disconnect("Protocol error waiting for X11 forwarding"); 1047 packet_disconnect("Protocol error waiting for X11 "
1048 "forwarding");
976 } 1049 }
977 } 1050 }
978 /* Tell the packet module whether this is an interactive session. */ 1051 /* Tell the packet module whether this is an interactive session. */
@@ -995,10 +1068,22 @@ ssh_session(void)
995 /* Initiate port forwardings. */ 1068 /* Initiate port forwardings. */
996 ssh_init_forwarding(); 1069 ssh_init_forwarding();
997 1070
998 /* If requested, let ssh continue in the background. */ 1071 /* Execute a local command */
999 if (fork_after_authentication_flag) 1072 if (options.local_command != NULL &&
1073 options.permit_local_command)
1074 ssh_local_cmd(options.local_command);
1075
1076 /*
1077 * If requested and we are not interested in replies to remote
1078 * forwarding requests, then let ssh continue in the background.
1079 */
1080 if (fork_after_authentication_flag &&
1081 (!options.exit_on_forward_failure ||
1082 options.num_remote_forwards == 0)) {
1083 fork_after_authentication_flag = 0;
1000 if (daemon(1, 1) < 0) 1084 if (daemon(1, 1) < 0)
1001 fatal("daemon() failed: %.200s", strerror(errno)); 1085 fatal("daemon() failed: %.200s", strerror(errno));
1086 }
1002 1087
1003 /* 1088 /*
1004 * If a command was specified on the command line, execute the 1089 * If a command was specified on the command line, execute the
@@ -1008,7 +1093,8 @@ ssh_session(void)
1008 int len = buffer_len(&command); 1093 int len = buffer_len(&command);
1009 if (len > 900) 1094 if (len > 900)
1010 len = 900; 1095 len = 900;
1011 debug("Sending command: %.*s", len, (u_char *)buffer_ptr(&command)); 1096 debug("Sending command: %.*s", len,
1097 (u_char *)buffer_ptr(&command));
1012 packet_start(SSH_CMSG_EXEC_CMD); 1098 packet_start(SSH_CMSG_EXEC_CMD);
1013 packet_put_string(buffer_ptr(&command), buffer_len(&command)); 1099 packet_put_string(buffer_ptr(&command), buffer_len(&command));
1014 packet_send(); 1100 packet_send();
@@ -1025,88 +1111,6 @@ ssh_session(void)
1025 options.escape_char : SSH_ESCAPECHAR_NONE, 0); 1111 options.escape_char : SSH_ESCAPECHAR_NONE, 0);
1026} 1112}
1027 1113
1028static void
1029ssh_subsystem_reply(int type, u_int32_t seq, void *ctxt)
1030{
1031 int id, len;
1032
1033 id = packet_get_int();
1034 len = buffer_len(&command);
1035 if (len > 900)
1036 len = 900;
1037 packet_check_eom();
1038 if (type == SSH2_MSG_CHANNEL_FAILURE)
1039 fatal("Request for subsystem '%.*s' failed on channel %d",
1040 len, (u_char *)buffer_ptr(&command), id);
1041}
1042
1043void
1044client_global_request_reply_fwd(int type, u_int32_t seq, void *ctxt)
1045{
1046 int i;
1047
1048 i = client_global_request_id++;
1049 if (i >= options.num_remote_forwards)
1050 return;
1051 debug("remote forward %s for: listen %d, connect %s:%d",
1052 type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure",
1053 options.remote_forwards[i].listen_port,
1054 options.remote_forwards[i].connect_host,
1055 options.remote_forwards[i].connect_port);
1056 if (type == SSH2_MSG_REQUEST_FAILURE) {
1057 if (options.exit_on_forward_failure)
1058 fatal("Error: remote port forwarding failed for "
1059 "listen port %d",
1060 options.remote_forwards[i].listen_port);
1061 else
1062 logit("Warning: remote port forwarding failed for "
1063 "listen port %d",
1064 options.remote_forwards[i].listen_port);
1065 }
1066}
1067
1068static void
1069ssh_control_listener(void)
1070{
1071 struct sockaddr_un addr;
1072 mode_t old_umask;
1073 int addr_len;
1074
1075 if (options.control_path == NULL ||
1076 options.control_master == SSHCTL_MASTER_NO)
1077 return;
1078
1079 debug("setting up multiplex master socket");
1080
1081 memset(&addr, '\0', sizeof(addr));
1082 addr.sun_family = AF_UNIX;
1083 addr_len = offsetof(struct sockaddr_un, sun_path) +
1084 strlen(options.control_path) + 1;
1085
1086 if (strlcpy(addr.sun_path, options.control_path,
1087 sizeof(addr.sun_path)) >= sizeof(addr.sun_path))
1088 fatal("ControlPath too long");
1089
1090 if ((control_fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
1091 fatal("%s socket(): %s", __func__, strerror(errno));
1092
1093 old_umask = umask(0177);
1094 if (bind(control_fd, (struct sockaddr *)&addr, addr_len) == -1) {
1095 control_fd = -1;
1096 if (errno == EINVAL || errno == EADDRINUSE)
1097 fatal("ControlSocket %s already exists",
1098 options.control_path);
1099 else
1100 fatal("%s bind(): %s", __func__, strerror(errno));
1101 }
1102 umask(old_umask);
1103
1104 if (listen(control_fd, 64) == -1)
1105 fatal("%s listen(): %s", __func__, strerror(errno));
1106
1107 set_nonblock(control_fd);
1108}
1109
1110/* request pty/x11/agent/tcpfwd/shell for channel */ 1114/* request pty/x11/agent/tcpfwd/shell for channel */
1111static void 1115static void
1112ssh_session2_setup(int id, void *arg) 1116ssh_session2_setup(int id, void *arg)
@@ -1122,7 +1126,8 @@ ssh_session2_setup(int id, void *arg)
1122 client_x11_get_proto(display, options.xauth_location, 1126 client_x11_get_proto(display, options.xauth_location,
1123 options.forward_x11_trusted, &proto, &data); 1127 options.forward_x11_trusted, &proto, &data);
1124 /* Request forwarding with authentication spoofing. */ 1128 /* Request forwarding with authentication spoofing. */
1125 debug("Requesting X11 forwarding with authentication spoofing."); 1129 debug("Requesting X11 forwarding with authentication "
1130 "spoofing.");
1126 x11_request_forwarding_with_spoofing(id, display, proto, data); 1131 x11_request_forwarding_with_spoofing(id, display, proto, data);
1127 interactive = 1; 1132 interactive = 1;
1128 /* XXX wait for reply */ 1133 /* XXX wait for reply */
@@ -1136,7 +1141,7 @@ ssh_session2_setup(int id, void *arg)
1136 } 1141 }
1137 1142
1138 client_session2_setup(id, tty_flag, subsystem_flag, getenv("TERM"), 1143 client_session2_setup(id, tty_flag, subsystem_flag, getenv("TERM"),
1139 NULL, fileno(stdin), &command, environ, &ssh_subsystem_reply); 1144 NULL, fileno(stdin), &command, environ);
1140 1145
1141 packet_set_interactive(interactive); 1146 packet_set_interactive(interactive);
1142} 1147}
@@ -1182,7 +1187,8 @@ ssh_session2_open(void)
1182 1187
1183 channel_send_open(c->self); 1188 channel_send_open(c->self);
1184 if (!no_shell_flag) 1189 if (!no_shell_flag)
1185 channel_register_confirm(c->self, ssh_session2_setup, NULL); 1190 channel_register_open_confirm(c->self,
1191 ssh_session2_setup, NULL);
1186 1192
1187 return c->self; 1193 return c->self;
1188} 1194}
@@ -1198,18 +1204,29 @@ ssh_session2(void)
1198 if (!no_shell_flag || (datafellows & SSH_BUG_DUMMYCHAN)) 1204 if (!no_shell_flag || (datafellows & SSH_BUG_DUMMYCHAN))
1199 id = ssh_session2_open(); 1205 id = ssh_session2_open();
1200 1206
1207 /* If we don't expect to open a new session, then disallow it */
1208 if (options.control_master == SSHCTL_MASTER_NO) {
1209 debug("Requesting no-more-sessions@openssh.com");
1210 packet_start(SSH2_MSG_GLOBAL_REQUEST);
1211 packet_put_cstring("no-more-sessions@openssh.com");
1212 packet_put_char(0);
1213 packet_send();
1214 }
1215
1201 /* Execute a local command */ 1216 /* Execute a local command */
1202 if (options.local_command != NULL && 1217 if (options.local_command != NULL &&
1203 options.permit_local_command) 1218 options.permit_local_command)
1204 ssh_local_cmd(options.local_command); 1219 ssh_local_cmd(options.local_command);
1205 1220
1206 /* Start listening for multiplex clients */ 1221 /* Start listening for multiplex clients */
1207 ssh_control_listener(); 1222 muxserver_listen();
1208 1223
1209 /* If requested, let ssh continue in the background. */ 1224 /* If requested, let ssh continue in the background. */
1210 if (fork_after_authentication_flag) 1225 if (fork_after_authentication_flag) {
1226 fork_after_authentication_flag = 0;
1211 if (daemon(1, 1) < 0) 1227 if (daemon(1, 1) < 0)
1212 fatal("daemon() failed: %.200s", strerror(errno)); 1228 fatal("daemon() failed: %.200s", strerror(errno));
1229 }
1213 1230
1214 return client_loop(tty_flag, tty_flag ? 1231 return client_loop(tty_flag, tty_flag ?
1215 options.escape_char : SSH_ESCAPECHAR_NONE, id); 1232 options.escape_char : SSH_ESCAPECHAR_NONE, id);
@@ -1219,6 +1236,7 @@ static void
1219load_public_identity_files(void) 1236load_public_identity_files(void)
1220{ 1237{
1221 char *filename, *cp, thishost[NI_MAXHOST], *fp; 1238 char *filename, *cp, thishost[NI_MAXHOST], *fp;
1239 char *pwdir = NULL, *pwname = NULL;
1222 int i = 0; 1240 int i = 0;
1223 Key *public; 1241 Key *public;
1224 struct passwd *pw; 1242 struct passwd *pw;
@@ -1231,9 +1249,11 @@ load_public_identity_files(void)
1231 int count = 0; 1249 int count = 0;
1232 for (i = 0; keys[i] != NULL; i++) { 1250 for (i = 0; keys[i] != NULL; i++) {
1233 count++; 1251 count++;
1234 memmove(&options.identity_files[1], &options.identity_files[0], 1252 memmove(&options.identity_files[1],
1253 &options.identity_files[0],
1235 sizeof(char *) * (SSH_MAX_IDENTITY_FILES - 1)); 1254 sizeof(char *) * (SSH_MAX_IDENTITY_FILES - 1));
1236 memmove(&options.identity_keys[1], &options.identity_keys[0], 1255 memmove(&options.identity_keys[1],
1256 &options.identity_keys[0],
1237 sizeof(Key *) * (SSH_MAX_IDENTITY_FILES - 1)); 1257 sizeof(Key *) * (SSH_MAX_IDENTITY_FILES - 1));
1238 options.num_identity_files++; 1258 options.num_identity_files++;
1239 options.identity_keys[0] = keys[i]; 1259 options.identity_keys[0] = keys[i];
@@ -1247,14 +1267,16 @@ load_public_identity_files(void)
1247#endif /* SMARTCARD */ 1267#endif /* SMARTCARD */
1248 if ((pw = getpwuid(original_real_uid)) == NULL) 1268 if ((pw = getpwuid(original_real_uid)) == NULL)
1249 fatal("load_public_identity_files: getpwuid failed"); 1269 fatal("load_public_identity_files: getpwuid failed");
1270 pwname = xstrdup(pw->pw_name);
1271 pwdir = xstrdup(pw->pw_dir);
1250 if (gethostname(thishost, sizeof(thishost)) == -1) 1272 if (gethostname(thishost, sizeof(thishost)) == -1)
1251 fatal("load_public_identity_files: gethostname: %s", 1273 fatal("load_public_identity_files: gethostname: %s",
1252 strerror(errno)); 1274 strerror(errno));
1253 for (; i < options.num_identity_files; i++) { 1275 for (; i < options.num_identity_files; i++) {
1254 cp = tilde_expand_filename(options.identity_files[i], 1276 cp = tilde_expand_filename(options.identity_files[i],
1255 original_real_uid); 1277 original_real_uid);
1256 filename = percent_expand(cp, "d", pw->pw_dir, 1278 filename = percent_expand(cp, "d", pwdir,
1257 "u", pw->pw_name, "l", thishost, "h", host, 1279 "u", pwname, "l", thishost, "h", host,
1258 "r", options.user, (char *)NULL); 1280 "r", options.user, (char *)NULL);
1259 xfree(cp); 1281 xfree(cp);
1260 public = key_load_public(filename, NULL); 1282 public = key_load_public(filename, NULL);
@@ -1280,231 +1302,8 @@ load_public_identity_files(void)
1280 options.identity_files[i] = filename; 1302 options.identity_files[i] = filename;
1281 options.identity_keys[i] = public; 1303 options.identity_keys[i] = public;
1282 } 1304 }
1283} 1305 bzero(pwname, strlen(pwname));
1284 1306 xfree(pwname);
1285static void 1307 bzero(pwdir, strlen(pwdir));
1286control_client_sighandler(int signo) 1308 xfree(pwdir);
1287{
1288 control_client_terminate = signo;
1289}
1290
1291static void
1292control_client_sigrelay(int signo)
1293{
1294 if (control_server_pid > 1)
1295 kill(control_server_pid, signo);
1296}
1297
1298static int
1299env_permitted(char *env)
1300{
1301 int i, ret;
1302 char name[1024], *cp;
1303
1304 if ((cp = strchr(env, '=')) == NULL || cp == env)
1305 return (0);
1306 ret = snprintf(name, sizeof(name), "%.*s", (int)(cp - env), env);
1307 if (ret <= 0 || (size_t)ret >= sizeof(name))
1308 fatal("env_permitted: name '%.100s...' too long", env);
1309
1310 for (i = 0; i < options.num_send_env; i++)
1311 if (match_pattern(name, options.send_env[i]))
1312 return (1);
1313
1314 return (0);
1315}
1316
1317static void
1318control_client(const char *path)
1319{
1320 struct sockaddr_un addr;
1321 int i, r, fd, sock, exitval[2], num_env, addr_len;
1322 Buffer m;
1323 char *term;
1324 extern char **environ;
1325 u_int flags;
1326
1327 if (mux_command == 0)
1328 mux_command = SSHMUX_COMMAND_OPEN;
1329
1330 switch (options.control_master) {
1331 case SSHCTL_MASTER_AUTO:
1332 case SSHCTL_MASTER_AUTO_ASK:
1333 debug("auto-mux: Trying existing master");
1334 /* FALLTHROUGH */
1335 case SSHCTL_MASTER_NO:
1336 break;
1337 default:
1338 return;
1339 }
1340
1341 memset(&addr, '\0', sizeof(addr));
1342 addr.sun_family = AF_UNIX;
1343 addr_len = offsetof(struct sockaddr_un, sun_path) +
1344 strlen(path) + 1;
1345
1346 if (strlcpy(addr.sun_path, path,
1347 sizeof(addr.sun_path)) >= sizeof(addr.sun_path))
1348 fatal("ControlPath too long");
1349
1350 if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
1351 fatal("%s socket(): %s", __func__, strerror(errno));
1352
1353 if (connect(sock, (struct sockaddr *)&addr, addr_len) == -1) {
1354 if (mux_command != SSHMUX_COMMAND_OPEN) {
1355 fatal("Control socket connect(%.100s): %s", path,
1356 strerror(errno));
1357 }
1358 if (errno == ENOENT)
1359 debug("Control socket \"%.100s\" does not exist", path);
1360 else {
1361 error("Control socket connect(%.100s): %s", path,
1362 strerror(errno));
1363 }
1364 close(sock);
1365 return;
1366 }
1367
1368 if (stdin_null_flag) {
1369 if ((fd = open(_PATH_DEVNULL, O_RDONLY)) == -1)
1370 fatal("open(/dev/null): %s", strerror(errno));
1371 if (dup2(fd, STDIN_FILENO) == -1)
1372 fatal("dup2: %s", strerror(errno));
1373 if (fd > STDERR_FILENO)
1374 close(fd);
1375 }
1376
1377 term = getenv("TERM");
1378
1379 flags = 0;
1380 if (tty_flag)
1381 flags |= SSHMUX_FLAG_TTY;
1382 if (subsystem_flag)
1383 flags |= SSHMUX_FLAG_SUBSYS;
1384 if (options.forward_x11)
1385 flags |= SSHMUX_FLAG_X11_FWD;
1386 if (options.forward_agent)
1387 flags |= SSHMUX_FLAG_AGENT_FWD;
1388
1389 buffer_init(&m);
1390
1391 /* Send our command to server */
1392 buffer_put_int(&m, mux_command);
1393 buffer_put_int(&m, flags);
1394 if (ssh_msg_send(sock, SSHMUX_VER, &m) == -1)
1395 fatal("%s: msg_send", __func__);
1396 buffer_clear(&m);
1397
1398 /* Get authorisation status and PID of controlee */
1399 if (ssh_msg_recv(sock, &m) == -1)
1400 fatal("%s: msg_recv", __func__);
1401 if (buffer_get_char(&m) != SSHMUX_VER)
1402 fatal("%s: wrong version", __func__);
1403 if (buffer_get_int(&m) != 1)
1404 fatal("Connection to master denied");
1405 control_server_pid = buffer_get_int(&m);
1406
1407 buffer_clear(&m);
1408
1409 switch (mux_command) {
1410 case SSHMUX_COMMAND_ALIVE_CHECK:
1411 fprintf(stderr, "Master running (pid=%d)\r\n",
1412 control_server_pid);
1413 exit(0);
1414 case SSHMUX_COMMAND_TERMINATE:
1415 fprintf(stderr, "Exit request sent.\r\n");
1416 exit(0);
1417 case SSHMUX_COMMAND_OPEN:
1418 /* continue below */
1419 break;
1420 default:
1421 fatal("silly mux_command %d", mux_command);
1422 }
1423
1424 /* SSHMUX_COMMAND_OPEN */
1425 buffer_put_cstring(&m, term ? term : "");
1426 buffer_append(&command, "\0", 1);
1427 buffer_put_cstring(&m, buffer_ptr(&command));
1428
1429 if (options.num_send_env == 0 || environ == NULL) {
1430 buffer_put_int(&m, 0);
1431 } else {
1432 /* Pass environment */
1433 num_env = 0;
1434 for (i = 0; environ[i] != NULL; i++)
1435 if (env_permitted(environ[i]))
1436 num_env++; /* Count */
1437
1438 buffer_put_int(&m, num_env);
1439
1440 for (i = 0; environ[i] != NULL && num_env >= 0; i++)
1441 if (env_permitted(environ[i])) {
1442 num_env--;
1443 buffer_put_cstring(&m, environ[i]);
1444 }
1445 }
1446
1447 if (ssh_msg_send(sock, SSHMUX_VER, &m) == -1)
1448 fatal("%s: msg_send", __func__);
1449
1450 mm_send_fd(sock, STDIN_FILENO);
1451 mm_send_fd(sock, STDOUT_FILENO);
1452 mm_send_fd(sock, STDERR_FILENO);
1453
1454 /* Wait for reply, so master has a chance to gather ttymodes */
1455 buffer_clear(&m);
1456 if (ssh_msg_recv(sock, &m) == -1)
1457 fatal("%s: msg_recv", __func__);
1458 if (buffer_get_char(&m) != SSHMUX_VER)
1459 fatal("%s: wrong version", __func__);
1460 buffer_free(&m);
1461
1462 signal(SIGHUP, control_client_sighandler);
1463 signal(SIGINT, control_client_sighandler);
1464 signal(SIGTERM, control_client_sighandler);
1465 signal(SIGWINCH, control_client_sigrelay);
1466
1467 if (tty_flag)
1468 enter_raw_mode();
1469
1470 /*
1471 * Stick around until the controlee closes the client_fd.
1472 * Before it does, it is expected to write this process' exit
1473 * value (one int). This process must read the value and wait for
1474 * the closure of the client_fd; if this one closes early, the
1475 * multiplex master will terminate early too (possibly losing data).
1476 */
1477 exitval[0] = 0;
1478 for (i = 0; !control_client_terminate && i < (int)sizeof(exitval);) {
1479 r = read(sock, (char *)exitval + i, sizeof(exitval) - i);
1480 if (r == 0) {
1481 debug2("Received EOF from master");
1482 break;
1483 }
1484 if (r == -1) {
1485 if (errno == EINTR)
1486 continue;
1487 fatal("%s: read %s", __func__, strerror(errno));
1488 }
1489 i += r;
1490 }
1491
1492 close(sock);
1493 leave_raw_mode();
1494 if (i > (int)sizeof(int))
1495 fatal("%s: master returned too much data (%d > %lu)",
1496 __func__, i, sizeof(int));
1497 if (control_client_terminate) {
1498 debug2("Exiting on signal %d", control_client_terminate);
1499 exitval[0] = 255;
1500 } else if (i < (int)sizeof(int)) {
1501 debug2("Control master terminated unexpectedly");
1502 exitval[0] = 255;
1503 } else
1504 debug2("Received exit status from master %d", exitval[0]);
1505
1506 if (tty_flag && options.log_level > SYSLOG_LEVEL_QUIET)
1507 fprintf(stderr, "Shared connection to %s closed.\r\n", host);
1508
1509 exit(exitval[0]);
1510} 1309}