diff options
author | Colin Watson <cjwatson@debian.org> | 2009-12-29 21:42:53 +0000 |
---|---|---|
committer | Colin Watson <cjwatson@debian.org> | 2009-12-29 21:42:53 +0000 |
commit | 87552344215a38d3a2b0d4d63dc151e05978bbe1 (patch) | |
tree | 9f4b96055e6ccaa915e8d59d9f2805e9e119371d /ssh.c | |
parent | a25ec0b132c44c9e341e08464ff830de06b81126 (diff) | |
parent | ef94e5613d37bcbf880f21ee6094e4b1c7683a4c (diff) |
import openssh-5.1p1-gsskex-cjwatson-20080722.patch
Diffstat (limited to 'ssh.c')
-rw-r--r-- | ssh.c | 541 |
1 files changed, 170 insertions, 371 deletions
@@ -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 | ||
108 | extern char *__progname; | 108 | extern 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. */ |
111 | int debug_flag = 0; | 111 | int 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; | |||
164 | int subsystem_flag = 0; | 164 | int subsystem_flag = 0; |
165 | 165 | ||
166 | /* # of replies received for global requests */ | 166 | /* # of replies received for global requests */ |
167 | static int client_global_request_id = 0; | 167 | static int remote_forward_confirms_received = 0; |
168 | 168 | ||
169 | /* pid of proxycommand child process */ | 169 | /* pid of proxycommand child process */ |
170 | pid_t proxy_command_pid = 0; | 170 | pid_t proxy_command_pid = 0; |
171 | 171 | ||
172 | /* fd to control socket */ | 172 | /* mux.c */ |
173 | int control_fd = -1; | 173 | extern int muxserver_sock; |
174 | 174 | extern u_int muxclient_command; | |
175 | /* Multiplexing control command */ | ||
176 | static u_int mux_command = 0; | ||
177 | |||
178 | /* Only used in control client mode */ | ||
179 | volatile sig_atomic_t control_client_terminate = 0; | ||
180 | u_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) | |||
198 | static int ssh_session(void); | 192 | static int ssh_session(void); |
199 | static int ssh_session2(void); | 193 | static int ssh_session2(void); |
200 | static void load_public_identity_files(void); | 194 | static void load_public_identity_files(void); |
201 | static void control_client(const char *path); | 195 | |
196 | /* from muxclient.c */ | ||
197 | void muxclient(const char *); | ||
198 | void 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; |
@@ -480,7 +481,8 @@ main(int ac, char **av) | |||
480 | } | 481 | } |
481 | if (cp != NULL) { | 482 | if (cp != NULL) { |
482 | fwd.listen_port = a2port(cp); | 483 | fwd.listen_port = a2port(cp); |
483 | fwd.listen_host = cleanhostname(fwd.listen_host); | 484 | fwd.listen_host = |
485 | cleanhostname(fwd.listen_host); | ||
484 | } else { | 486 | } else { |
485 | fwd.listen_port = a2port(fwd.listen_host); | 487 | fwd.listen_port = a2port(fwd.listen_host); |
486 | fwd.listen_host = NULL; | 488 | fwd.listen_host = NULL; |
@@ -586,8 +588,10 @@ main(int ac, char **av) | |||
586 | } | 588 | } |
587 | 589 | ||
588 | /* Cannot fork to background if no command. */ | 590 | /* Cannot fork to background if no command. */ |
589 | if (fork_after_authentication_flag && buffer_len(&command) == 0 && !no_shell_flag) | 591 | if (fork_after_authentication_flag && buffer_len(&command) == 0 && |
590 | fatal("Cannot fork into background without a command to execute."); | 592 | !no_shell_flag) |
593 | fatal("Cannot fork into background without a command " | ||
594 | "to execute."); | ||
591 | 595 | ||
592 | /* Allocate a tty by default if no command specified. */ | 596 | /* Allocate a tty by default if no command specified. */ |
593 | if (buffer_len(&command) == 0) | 597 | if (buffer_len(&command) == 0) |
@@ -599,7 +603,8 @@ main(int ac, char **av) | |||
599 | /* Do not allocate a tty if stdin is not a tty. */ | 603 | /* Do not allocate a tty if stdin is not a tty. */ |
600 | if ((!isatty(fileno(stdin)) || stdin_null_flag) && !force_tty_flag) { | 604 | if ((!isatty(fileno(stdin)) || stdin_null_flag) && !force_tty_flag) { |
601 | if (tty_flag) | 605 | if (tty_flag) |
602 | logit("Pseudo-terminal will not be allocated because stdin is not a terminal."); | 606 | logit("Pseudo-terminal will not be allocated because " |
607 | "stdin is not a terminal."); | ||
603 | tty_flag = 0; | 608 | tty_flag = 0; |
604 | } | 609 | } |
605 | 610 | ||
@@ -607,7 +612,8 @@ main(int ac, char **av) | |||
607 | * Initialize "log" output. Since we are the client all output | 612 | * Initialize "log" output. Since we are the client all output |
608 | * actually goes to stderr. | 613 | * actually goes to stderr. |
609 | */ | 614 | */ |
610 | log_init(av[0], options.log_level == -1 ? SYSLOG_LEVEL_INFO : options.log_level, | 615 | log_init(av[0], |
616 | options.log_level == -1 ? SYSLOG_LEVEL_INFO : options.log_level, | ||
611 | SYSLOG_FACILITY_USER, 1); | 617 | SYSLOG_FACILITY_USER, 1); |
612 | 618 | ||
613 | /* | 619 | /* |
@@ -641,6 +647,28 @@ main(int ac, char **av) | |||
641 | if (options.user == NULL) | 647 | if (options.user == NULL) |
642 | options.user = xstrdup(pw->pw_name); | 648 | options.user = xstrdup(pw->pw_name); |
643 | 649 | ||
650 | /* Get default port if port has not been set. */ | ||
651 | if (options.port == 0) { | ||
652 | sp = getservbyname(SSH_SERVICE_NAME, "tcp"); | ||
653 | options.port = sp ? ntohs(sp->s_port) : SSH_DEFAULT_PORT; | ||
654 | } | ||
655 | |||
656 | if (options.local_command != NULL) { | ||
657 | char thishost[NI_MAXHOST]; | ||
658 | |||
659 | if (gethostname(thishost, sizeof(thishost)) == -1) | ||
660 | fatal("gethostname: %s", strerror(errno)); | ||
661 | snprintf(buf, sizeof(buf), "%d", options.port); | ||
662 | debug3("expanding LocalCommand: %s", options.local_command); | ||
663 | cp = options.local_command; | ||
664 | options.local_command = percent_expand(cp, "d", pw->pw_dir, | ||
665 | "h", options.hostname? options.hostname : host, | ||
666 | "l", thishost, "n", host, "r", options.user, "p", buf, | ||
667 | "u", pw->pw_name, (char *)NULL); | ||
668 | debug3("expanded LocalCommand: %s", options.local_command); | ||
669 | xfree(cp); | ||
670 | } | ||
671 | |||
644 | if (options.hostname != NULL) | 672 | if (options.hostname != NULL) |
645 | host = options.hostname; | 673 | host = options.hostname; |
646 | 674 | ||
@@ -651,18 +679,16 @@ main(int ac, char **av) | |||
651 | *p = (char)tolower(*p); | 679 | *p = (char)tolower(*p); |
652 | } | 680 | } |
653 | 681 | ||
654 | /* Get default port if port has not been set. */ | ||
655 | if (options.port == 0) { | ||
656 | sp = getservbyname(SSH_SERVICE_NAME, "tcp"); | ||
657 | options.port = sp ? ntohs(sp->s_port) : SSH_DEFAULT_PORT; | ||
658 | } | ||
659 | |||
660 | if (options.proxy_command != NULL && | 682 | if (options.proxy_command != NULL && |
661 | strcmp(options.proxy_command, "none") == 0) | 683 | strcmp(options.proxy_command, "none") == 0) { |
684 | xfree(options.proxy_command); | ||
662 | options.proxy_command = NULL; | 685 | options.proxy_command = NULL; |
686 | } | ||
663 | if (options.control_path != NULL && | 687 | if (options.control_path != NULL && |
664 | strcmp(options.control_path, "none") == 0) | 688 | strcmp(options.control_path, "none") == 0) { |
689 | xfree(options.control_path); | ||
665 | options.control_path = NULL; | 690 | options.control_path = NULL; |
691 | } | ||
666 | 692 | ||
667 | if (options.control_path != NULL) { | 693 | if (options.control_path != NULL) { |
668 | char thishost[NI_MAXHOST]; | 694 | char thishost[NI_MAXHOST]; |
@@ -672,18 +698,22 @@ main(int ac, char **av) | |||
672 | snprintf(buf, sizeof(buf), "%d", options.port); | 698 | snprintf(buf, sizeof(buf), "%d", options.port); |
673 | cp = tilde_expand_filename(options.control_path, | 699 | cp = tilde_expand_filename(options.control_path, |
674 | original_real_uid); | 700 | original_real_uid); |
701 | xfree(options.control_path); | ||
675 | options.control_path = percent_expand(cp, "p", buf, "h", host, | 702 | options.control_path = percent_expand(cp, "p", buf, "h", host, |
676 | "r", options.user, "l", thishost, (char *)NULL); | 703 | "r", options.user, "l", thishost, (char *)NULL); |
677 | xfree(cp); | 704 | xfree(cp); |
678 | } | 705 | } |
679 | if (mux_command != 0 && options.control_path == NULL) | 706 | if (muxclient_command != 0 && options.control_path == NULL) |
680 | fatal("No ControlPath specified for \"-O\" command"); | 707 | fatal("No ControlPath specified for \"-O\" command"); |
681 | if (options.control_path != NULL) | 708 | if (options.control_path != NULL) |
682 | control_client(options.control_path); | 709 | muxclient(options.control_path); |
710 | |||
711 | timeout_ms = options.connection_timeout * 1000; | ||
683 | 712 | ||
684 | /* Open a connection to the remote host. */ | 713 | /* Open a connection to the remote host. */ |
685 | if (ssh_connect(host, &hostaddr, options.port, | 714 | if (ssh_connect(host, &hostaddr, options.port, |
686 | options.address_family, options.connection_attempts, | 715 | options.address_family, options.connection_attempts, &timeout_ms, |
716 | options.tcp_keep_alive, | ||
687 | #ifdef HAVE_CYGWIN | 717 | #ifdef HAVE_CYGWIN |
688 | options.use_privileged_port, | 718 | options.use_privileged_port, |
689 | #else | 719 | #else |
@@ -692,6 +722,9 @@ main(int ac, char **av) | |||
692 | options.proxy_command) != 0) | 722 | options.proxy_command) != 0) |
693 | exit(255); | 723 | exit(255); |
694 | 724 | ||
725 | if (timeout_ms > 0) | ||
726 | debug3("timeout: %d ms remain after connect", timeout_ms); | ||
727 | |||
695 | /* | 728 | /* |
696 | * If we successfully made the connection, load the host private key | 729 | * If we successfully made the connection, load the host private key |
697 | * in case we will need it later for combined rsa-rhosts | 730 | * in case we will need it later for combined rsa-rhosts |
@@ -745,7 +778,8 @@ main(int ac, char **av) | |||
745 | * Now that we are back to our own permissions, create ~/.ssh | 778 | * Now that we are back to our own permissions, create ~/.ssh |
746 | * directory if it doesn't already exist. | 779 | * directory if it doesn't already exist. |
747 | */ | 780 | */ |
748 | snprintf(buf, sizeof buf, "%.100s%s%.100s", pw->pw_dir, strcmp(pw->pw_dir, "/") ? "/" : "", _PATH_SSH_USER_DIR); | 781 | snprintf(buf, sizeof buf, "%.100s%s%.100s", pw->pw_dir, |
782 | strcmp(pw->pw_dir, "/") ? "/" : "", _PATH_SSH_USER_DIR); | ||
749 | if (stat(buf, &st) < 0) | 783 | if (stat(buf, &st) < 0) |
750 | if (mkdir(buf, 0700) < 0) | 784 | if (mkdir(buf, 0700) < 0) |
751 | error("Could not create directory '%.200s'.", buf); | 785 | error("Could not create directory '%.200s'.", buf); |
@@ -766,8 +800,9 @@ main(int ac, char **av) | |||
766 | 800 | ||
767 | signal(SIGPIPE, SIG_IGN); /* ignore SIGPIPE early */ | 801 | signal(SIGPIPE, SIG_IGN); /* ignore SIGPIPE early */ |
768 | 802 | ||
769 | /* Log into the remote system. This never returns if the login fails. */ | 803 | /* Log into the remote system. Never returns if the login fails. */ |
770 | ssh_login(&sensitive_data, host, (struct sockaddr *)&hostaddr, pw); | 804 | ssh_login(&sensitive_data, host, (struct sockaddr *)&hostaddr, |
805 | pw, timeout_ms); | ||
771 | 806 | ||
772 | /* We no longer need the private host keys. Clear them now. */ | 807 | /* We no longer need the private host keys. Clear them now. */ |
773 | if (sensitive_data.nkeys != 0) { | 808 | if (sensitive_data.nkeys != 0) { |
@@ -795,7 +830,7 @@ main(int ac, char **av) | |||
795 | exit_status = compat20 ? ssh_session2() : ssh_session(); | 830 | exit_status = compat20 ? ssh_session2() : ssh_session(); |
796 | packet_close(); | 831 | packet_close(); |
797 | 832 | ||
798 | if (options.control_path != NULL && control_fd != -1) | 833 | if (options.control_path != NULL && muxserver_sock != -1) |
799 | unlink(options.control_path); | 834 | unlink(options.control_path); |
800 | 835 | ||
801 | /* | 836 | /* |
@@ -808,6 +843,34 @@ main(int ac, char **av) | |||
808 | return exit_status; | 843 | return exit_status; |
809 | } | 844 | } |
810 | 845 | ||
846 | /* Callback for remote forward global requests */ | ||
847 | static void | ||
848 | ssh_confirm_remote_forward(int type, u_int32_t seq, void *ctxt) | ||
849 | { | ||
850 | Forward *rfwd = (Forward *)ctxt; | ||
851 | |||
852 | debug("remote forward %s for: listen %d, connect %s:%d", | ||
853 | type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure", | ||
854 | rfwd->listen_port, rfwd->connect_host, rfwd->connect_port); | ||
855 | if (type == SSH2_MSG_REQUEST_FAILURE) { | ||
856 | if (options.exit_on_forward_failure) | ||
857 | fatal("Error: remote port forwarding failed for " | ||
858 | "listen port %d", rfwd->listen_port); | ||
859 | else | ||
860 | logit("Warning: remote port forwarding failed for " | ||
861 | "listen port %d", rfwd->listen_port); | ||
862 | } | ||
863 | if (++remote_forward_confirms_received == options.num_remote_forwards) { | ||
864 | debug("All remote forwarding requests processed"); | ||
865 | if (fork_after_authentication_flag) { | ||
866 | fork_after_authentication_flag = 0; | ||
867 | if (daemon(1, 1) < 0) | ||
868 | fatal("daemon() failed: %.200s", | ||
869 | strerror(errno)); | ||
870 | } | ||
871 | } | ||
872 | } | ||
873 | |||
811 | static void | 874 | static void |
812 | ssh_init_forwarding(void) | 875 | ssh_init_forwarding(void) |
813 | { | 876 | { |
@@ -856,6 +919,8 @@ ssh_init_forwarding(void) | |||
856 | logit("Warning: Could not request remote " | 919 | logit("Warning: Could not request remote " |
857 | "forwarding."); | 920 | "forwarding."); |
858 | } | 921 | } |
922 | client_register_global_confirm(ssh_confirm_remote_forward, | ||
923 | &options.remote_forwards[i]); | ||
859 | } | 924 | } |
860 | 925 | ||
861 | /* Initiate tunnel forwarding. */ | 926 | /* Initiate tunnel forwarding. */ |
@@ -892,10 +957,13 @@ ssh_session(void) | |||
892 | 957 | ||
893 | /* Enable compression if requested. */ | 958 | /* Enable compression if requested. */ |
894 | if (options.compression) { | 959 | if (options.compression) { |
895 | debug("Requesting compression at level %d.", options.compression_level); | 960 | debug("Requesting compression at level %d.", |
961 | options.compression_level); | ||
896 | 962 | ||
897 | if (options.compression_level < 1 || options.compression_level > 9) | 963 | if (options.compression_level < 1 || |
898 | fatal("Compression level must be from 1 (fast) to 9 (slow, best)."); | 964 | options.compression_level > 9) |
965 | fatal("Compression level must be from 1 (fast) to " | ||
966 | "9 (slow, best)."); | ||
899 | 967 | ||
900 | /* Send the request. */ | 968 | /* Send the request. */ |
901 | packet_start(SSH_CMSG_REQUEST_COMPRESSION); | 969 | packet_start(SSH_CMSG_REQUEST_COMPRESSION); |
@@ -908,7 +976,8 @@ ssh_session(void) | |||
908 | else if (type == SSH_SMSG_FAILURE) | 976 | else if (type == SSH_SMSG_FAILURE) |
909 | logit("Warning: Remote host refused compression."); | 977 | logit("Warning: Remote host refused compression."); |
910 | else | 978 | else |
911 | packet_disconnect("Protocol error waiting for compression response."); | 979 | packet_disconnect("Protocol error waiting for " |
980 | "compression response."); | ||
912 | } | 981 | } |
913 | /* Allocate a pseudo tty if appropriate. */ | 982 | /* Allocate a pseudo tty if appropriate. */ |
914 | if (tty_flag) { | 983 | if (tty_flag) { |
@@ -945,9 +1014,11 @@ ssh_session(void) | |||
945 | interactive = 1; | 1014 | interactive = 1; |
946 | have_tty = 1; | 1015 | have_tty = 1; |
947 | } else if (type == SSH_SMSG_FAILURE) | 1016 | } else if (type == SSH_SMSG_FAILURE) |
948 | logit("Warning: Remote host failed or refused to allocate a pseudo tty."); | 1017 | logit("Warning: Remote host failed or refused to " |
1018 | "allocate a pseudo tty."); | ||
949 | else | 1019 | else |
950 | packet_disconnect("Protocol error waiting for pty request response."); | 1020 | packet_disconnect("Protocol error waiting for pty " |
1021 | "request response."); | ||
951 | } | 1022 | } |
952 | /* Request X11 forwarding if enabled and DISPLAY is set. */ | 1023 | /* Request X11 forwarding if enabled and DISPLAY is set. */ |
953 | display = getenv("DISPLAY"); | 1024 | display = getenv("DISPLAY"); |
@@ -957,7 +1028,8 @@ ssh_session(void) | |||
957 | client_x11_get_proto(display, options.xauth_location, | 1028 | client_x11_get_proto(display, options.xauth_location, |
958 | options.forward_x11_trusted, &proto, &data); | 1029 | options.forward_x11_trusted, &proto, &data); |
959 | /* Request forwarding with authentication spoofing. */ | 1030 | /* Request forwarding with authentication spoofing. */ |
960 | debug("Requesting X11 forwarding with authentication spoofing."); | 1031 | debug("Requesting X11 forwarding with authentication " |
1032 | "spoofing."); | ||
961 | x11_request_forwarding_with_spoofing(0, display, proto, data); | 1033 | x11_request_forwarding_with_spoofing(0, display, proto, data); |
962 | 1034 | ||
963 | /* Read response from the server. */ | 1035 | /* Read response from the server. */ |
@@ -967,7 +1039,8 @@ ssh_session(void) | |||
967 | } else if (type == SSH_SMSG_FAILURE) { | 1039 | } else if (type == SSH_SMSG_FAILURE) { |
968 | logit("Warning: Remote host denied X11 forwarding."); | 1040 | logit("Warning: Remote host denied X11 forwarding."); |
969 | } else { | 1041 | } else { |
970 | packet_disconnect("Protocol error waiting for X11 forwarding"); | 1042 | packet_disconnect("Protocol error waiting for X11 " |
1043 | "forwarding"); | ||
971 | } | 1044 | } |
972 | } | 1045 | } |
973 | /* Tell the packet module whether this is an interactive session. */ | 1046 | /* Tell the packet module whether this is an interactive session. */ |
@@ -990,10 +1063,22 @@ ssh_session(void) | |||
990 | /* Initiate port forwardings. */ | 1063 | /* Initiate port forwardings. */ |
991 | ssh_init_forwarding(); | 1064 | ssh_init_forwarding(); |
992 | 1065 | ||
993 | /* If requested, let ssh continue in the background. */ | 1066 | /* Execute a local command */ |
994 | if (fork_after_authentication_flag) | 1067 | if (options.local_command != NULL && |
1068 | options.permit_local_command) | ||
1069 | ssh_local_cmd(options.local_command); | ||
1070 | |||
1071 | /* | ||
1072 | * If requested and we are not interested in replies to remote | ||
1073 | * forwarding requests, then let ssh continue in the background. | ||
1074 | */ | ||
1075 | if (fork_after_authentication_flag && | ||
1076 | (!options.exit_on_forward_failure || | ||
1077 | options.num_remote_forwards == 0)) { | ||
1078 | fork_after_authentication_flag = 0; | ||
995 | if (daemon(1, 1) < 0) | 1079 | if (daemon(1, 1) < 0) |
996 | fatal("daemon() failed: %.200s", strerror(errno)); | 1080 | fatal("daemon() failed: %.200s", strerror(errno)); |
1081 | } | ||
997 | 1082 | ||
998 | /* | 1083 | /* |
999 | * If a command was specified on the command line, execute the | 1084 | * If a command was specified on the command line, execute the |
@@ -1003,7 +1088,8 @@ ssh_session(void) | |||
1003 | int len = buffer_len(&command); | 1088 | int len = buffer_len(&command); |
1004 | if (len > 900) | 1089 | if (len > 900) |
1005 | len = 900; | 1090 | len = 900; |
1006 | debug("Sending command: %.*s", len, (u_char *)buffer_ptr(&command)); | 1091 | debug("Sending command: %.*s", len, |
1092 | (u_char *)buffer_ptr(&command)); | ||
1007 | packet_start(SSH_CMSG_EXEC_CMD); | 1093 | packet_start(SSH_CMSG_EXEC_CMD); |
1008 | packet_put_string(buffer_ptr(&command), buffer_len(&command)); | 1094 | packet_put_string(buffer_ptr(&command), buffer_len(&command)); |
1009 | packet_send(); | 1095 | packet_send(); |
@@ -1020,88 +1106,6 @@ ssh_session(void) | |||
1020 | options.escape_char : SSH_ESCAPECHAR_NONE, 0); | 1106 | options.escape_char : SSH_ESCAPECHAR_NONE, 0); |
1021 | } | 1107 | } |
1022 | 1108 | ||
1023 | static void | ||
1024 | ssh_subsystem_reply(int type, u_int32_t seq, void *ctxt) | ||
1025 | { | ||
1026 | int id, len; | ||
1027 | |||
1028 | id = packet_get_int(); | ||
1029 | len = buffer_len(&command); | ||
1030 | if (len > 900) | ||
1031 | len = 900; | ||
1032 | packet_check_eom(); | ||
1033 | if (type == SSH2_MSG_CHANNEL_FAILURE) | ||
1034 | fatal("Request for subsystem '%.*s' failed on channel %d", | ||
1035 | len, (u_char *)buffer_ptr(&command), id); | ||
1036 | } | ||
1037 | |||
1038 | void | ||
1039 | client_global_request_reply_fwd(int type, u_int32_t seq, void *ctxt) | ||
1040 | { | ||
1041 | int i; | ||
1042 | |||
1043 | i = client_global_request_id++; | ||
1044 | if (i >= options.num_remote_forwards) | ||
1045 | return; | ||
1046 | debug("remote forward %s for: listen %d, connect %s:%d", | ||
1047 | type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure", | ||
1048 | options.remote_forwards[i].listen_port, | ||
1049 | options.remote_forwards[i].connect_host, | ||
1050 | options.remote_forwards[i].connect_port); | ||
1051 | if (type == SSH2_MSG_REQUEST_FAILURE) { | ||
1052 | if (options.exit_on_forward_failure) | ||
1053 | fatal("Error: remote port forwarding failed for " | ||
1054 | "listen port %d", | ||
1055 | options.remote_forwards[i].listen_port); | ||
1056 | else | ||
1057 | logit("Warning: remote port forwarding failed for " | ||
1058 | "listen port %d", | ||
1059 | options.remote_forwards[i].listen_port); | ||
1060 | } | ||
1061 | } | ||
1062 | |||
1063 | static void | ||
1064 | ssh_control_listener(void) | ||
1065 | { | ||
1066 | struct sockaddr_un addr; | ||
1067 | mode_t old_umask; | ||
1068 | int addr_len; | ||
1069 | |||
1070 | if (options.control_path == NULL || | ||
1071 | options.control_master == SSHCTL_MASTER_NO) | ||
1072 | return; | ||
1073 | |||
1074 | debug("setting up multiplex master socket"); | ||
1075 | |||
1076 | memset(&addr, '\0', sizeof(addr)); | ||
1077 | addr.sun_family = AF_UNIX; | ||
1078 | addr_len = offsetof(struct sockaddr_un, sun_path) + | ||
1079 | strlen(options.control_path) + 1; | ||
1080 | |||
1081 | if (strlcpy(addr.sun_path, options.control_path, | ||
1082 | sizeof(addr.sun_path)) >= sizeof(addr.sun_path)) | ||
1083 | fatal("ControlPath too long"); | ||
1084 | |||
1085 | if ((control_fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) | ||
1086 | fatal("%s socket(): %s", __func__, strerror(errno)); | ||
1087 | |||
1088 | old_umask = umask(0177); | ||
1089 | if (bind(control_fd, (struct sockaddr *)&addr, addr_len) == -1) { | ||
1090 | control_fd = -1; | ||
1091 | if (errno == EINVAL || errno == EADDRINUSE) | ||
1092 | fatal("ControlSocket %s already exists", | ||
1093 | options.control_path); | ||
1094 | else | ||
1095 | fatal("%s bind(): %s", __func__, strerror(errno)); | ||
1096 | } | ||
1097 | umask(old_umask); | ||
1098 | |||
1099 | if (listen(control_fd, 64) == -1) | ||
1100 | fatal("%s listen(): %s", __func__, strerror(errno)); | ||
1101 | |||
1102 | set_nonblock(control_fd); | ||
1103 | } | ||
1104 | |||
1105 | /* request pty/x11/agent/tcpfwd/shell for channel */ | 1109 | /* request pty/x11/agent/tcpfwd/shell for channel */ |
1106 | static void | 1110 | static void |
1107 | ssh_session2_setup(int id, void *arg) | 1111 | ssh_session2_setup(int id, void *arg) |
@@ -1117,7 +1121,8 @@ ssh_session2_setup(int id, void *arg) | |||
1117 | client_x11_get_proto(display, options.xauth_location, | 1121 | client_x11_get_proto(display, options.xauth_location, |
1118 | options.forward_x11_trusted, &proto, &data); | 1122 | options.forward_x11_trusted, &proto, &data); |
1119 | /* Request forwarding with authentication spoofing. */ | 1123 | /* Request forwarding with authentication spoofing. */ |
1120 | debug("Requesting X11 forwarding with authentication spoofing."); | 1124 | debug("Requesting X11 forwarding with authentication " |
1125 | "spoofing."); | ||
1121 | x11_request_forwarding_with_spoofing(id, display, proto, data); | 1126 | x11_request_forwarding_with_spoofing(id, display, proto, data); |
1122 | interactive = 1; | 1127 | interactive = 1; |
1123 | /* XXX wait for reply */ | 1128 | /* XXX wait for reply */ |
@@ -1131,7 +1136,7 @@ ssh_session2_setup(int id, void *arg) | |||
1131 | } | 1136 | } |
1132 | 1137 | ||
1133 | client_session2_setup(id, tty_flag, subsystem_flag, getenv("TERM"), | 1138 | client_session2_setup(id, tty_flag, subsystem_flag, getenv("TERM"), |
1134 | NULL, fileno(stdin), &command, environ, &ssh_subsystem_reply); | 1139 | NULL, fileno(stdin), &command, environ); |
1135 | 1140 | ||
1136 | packet_set_interactive(interactive); | 1141 | packet_set_interactive(interactive); |
1137 | } | 1142 | } |
@@ -1177,7 +1182,8 @@ ssh_session2_open(void) | |||
1177 | 1182 | ||
1178 | channel_send_open(c->self); | 1183 | channel_send_open(c->self); |
1179 | if (!no_shell_flag) | 1184 | if (!no_shell_flag) |
1180 | channel_register_confirm(c->self, ssh_session2_setup, NULL); | 1185 | channel_register_open_confirm(c->self, |
1186 | ssh_session2_setup, NULL); | ||
1181 | 1187 | ||
1182 | return c->self; | 1188 | return c->self; |
1183 | } | 1189 | } |
@@ -1193,18 +1199,29 @@ ssh_session2(void) | |||
1193 | if (!no_shell_flag || (datafellows & SSH_BUG_DUMMYCHAN)) | 1199 | if (!no_shell_flag || (datafellows & SSH_BUG_DUMMYCHAN)) |
1194 | id = ssh_session2_open(); | 1200 | id = ssh_session2_open(); |
1195 | 1201 | ||
1202 | /* If we don't expect to open a new session, then disallow it */ | ||
1203 | if (options.control_master == SSHCTL_MASTER_NO) { | ||
1204 | debug("Requesting no-more-sessions@openssh.com"); | ||
1205 | packet_start(SSH2_MSG_GLOBAL_REQUEST); | ||
1206 | packet_put_cstring("no-more-sessions@openssh.com"); | ||
1207 | packet_put_char(0); | ||
1208 | packet_send(); | ||
1209 | } | ||
1210 | |||
1196 | /* Execute a local command */ | 1211 | /* Execute a local command */ |
1197 | if (options.local_command != NULL && | 1212 | if (options.local_command != NULL && |
1198 | options.permit_local_command) | 1213 | options.permit_local_command) |
1199 | ssh_local_cmd(options.local_command); | 1214 | ssh_local_cmd(options.local_command); |
1200 | 1215 | ||
1201 | /* Start listening for multiplex clients */ | 1216 | /* Start listening for multiplex clients */ |
1202 | ssh_control_listener(); | 1217 | muxserver_listen(); |
1203 | 1218 | ||
1204 | /* If requested, let ssh continue in the background. */ | 1219 | /* If requested, let ssh continue in the background. */ |
1205 | if (fork_after_authentication_flag) | 1220 | if (fork_after_authentication_flag) { |
1221 | fork_after_authentication_flag = 0; | ||
1206 | if (daemon(1, 1) < 0) | 1222 | if (daemon(1, 1) < 0) |
1207 | fatal("daemon() failed: %.200s", strerror(errno)); | 1223 | fatal("daemon() failed: %.200s", strerror(errno)); |
1224 | } | ||
1208 | 1225 | ||
1209 | return client_loop(tty_flag, tty_flag ? | 1226 | return client_loop(tty_flag, tty_flag ? |
1210 | options.escape_char : SSH_ESCAPECHAR_NONE, id); | 1227 | options.escape_char : SSH_ESCAPECHAR_NONE, id); |
@@ -1214,6 +1231,7 @@ static void | |||
1214 | load_public_identity_files(void) | 1231 | load_public_identity_files(void) |
1215 | { | 1232 | { |
1216 | char *filename, *cp, thishost[NI_MAXHOST]; | 1233 | char *filename, *cp, thishost[NI_MAXHOST]; |
1234 | char *pwdir = NULL, *pwname = NULL; | ||
1217 | int i = 0; | 1235 | int i = 0; |
1218 | Key *public; | 1236 | Key *public; |
1219 | struct passwd *pw; | 1237 | struct passwd *pw; |
@@ -1226,9 +1244,11 @@ load_public_identity_files(void) | |||
1226 | int count = 0; | 1244 | int count = 0; |
1227 | for (i = 0; keys[i] != NULL; i++) { | 1245 | for (i = 0; keys[i] != NULL; i++) { |
1228 | count++; | 1246 | count++; |
1229 | memmove(&options.identity_files[1], &options.identity_files[0], | 1247 | memmove(&options.identity_files[1], |
1248 | &options.identity_files[0], | ||
1230 | sizeof(char *) * (SSH_MAX_IDENTITY_FILES - 1)); | 1249 | sizeof(char *) * (SSH_MAX_IDENTITY_FILES - 1)); |
1231 | memmove(&options.identity_keys[1], &options.identity_keys[0], | 1250 | memmove(&options.identity_keys[1], |
1251 | &options.identity_keys[0], | ||
1232 | sizeof(Key *) * (SSH_MAX_IDENTITY_FILES - 1)); | 1252 | sizeof(Key *) * (SSH_MAX_IDENTITY_FILES - 1)); |
1233 | options.num_identity_files++; | 1253 | options.num_identity_files++; |
1234 | options.identity_keys[0] = keys[i]; | 1254 | options.identity_keys[0] = keys[i]; |
@@ -1242,14 +1262,16 @@ load_public_identity_files(void) | |||
1242 | #endif /* SMARTCARD */ | 1262 | #endif /* SMARTCARD */ |
1243 | if ((pw = getpwuid(original_real_uid)) == NULL) | 1263 | if ((pw = getpwuid(original_real_uid)) == NULL) |
1244 | fatal("load_public_identity_files: getpwuid failed"); | 1264 | fatal("load_public_identity_files: getpwuid failed"); |
1265 | pwname = xstrdup(pw->pw_name); | ||
1266 | pwdir = xstrdup(pw->pw_dir); | ||
1245 | if (gethostname(thishost, sizeof(thishost)) == -1) | 1267 | if (gethostname(thishost, sizeof(thishost)) == -1) |
1246 | fatal("load_public_identity_files: gethostname: %s", | 1268 | fatal("load_public_identity_files: gethostname: %s", |
1247 | strerror(errno)); | 1269 | strerror(errno)); |
1248 | for (; i < options.num_identity_files; i++) { | 1270 | for (; i < options.num_identity_files; i++) { |
1249 | cp = tilde_expand_filename(options.identity_files[i], | 1271 | cp = tilde_expand_filename(options.identity_files[i], |
1250 | original_real_uid); | 1272 | original_real_uid); |
1251 | filename = percent_expand(cp, "d", pw->pw_dir, | 1273 | filename = percent_expand(cp, "d", pwdir, |
1252 | "u", pw->pw_name, "l", thishost, "h", host, | 1274 | "u", pwname, "l", thishost, "h", host, |
1253 | "r", options.user, (char *)NULL); | 1275 | "r", options.user, (char *)NULL); |
1254 | xfree(cp); | 1276 | xfree(cp); |
1255 | public = key_load_public(filename, NULL); | 1277 | public = key_load_public(filename, NULL); |
@@ -1259,231 +1281,8 @@ load_public_identity_files(void) | |||
1259 | options.identity_files[i] = filename; | 1281 | options.identity_files[i] = filename; |
1260 | options.identity_keys[i] = public; | 1282 | options.identity_keys[i] = public; |
1261 | } | 1283 | } |
1262 | } | 1284 | bzero(pwname, strlen(pwname)); |
1263 | 1285 | xfree(pwname); | |
1264 | static void | 1286 | bzero(pwdir, strlen(pwdir)); |
1265 | control_client_sighandler(int signo) | 1287 | xfree(pwdir); |
1266 | { | ||
1267 | control_client_terminate = signo; | ||
1268 | } | ||
1269 | |||
1270 | static void | ||
1271 | control_client_sigrelay(int signo) | ||
1272 | { | ||
1273 | if (control_server_pid > 1) | ||
1274 | kill(control_server_pid, signo); | ||
1275 | } | ||
1276 | |||
1277 | static int | ||
1278 | env_permitted(char *env) | ||
1279 | { | ||
1280 | int i, ret; | ||
1281 | char name[1024], *cp; | ||
1282 | |||
1283 | if ((cp = strchr(env, '=')) == NULL || cp == env) | ||
1284 | return (0); | ||
1285 | ret = snprintf(name, sizeof(name), "%.*s", (int)(cp - env), env); | ||
1286 | if (ret <= 0 || (size_t)ret >= sizeof(name)) | ||
1287 | fatal("env_permitted: name '%.100s...' too long", env); | ||
1288 | |||
1289 | for (i = 0; i < options.num_send_env; i++) | ||
1290 | if (match_pattern(name, options.send_env[i])) | ||
1291 | return (1); | ||
1292 | |||
1293 | return (0); | ||
1294 | } | ||
1295 | |||
1296 | static void | ||
1297 | control_client(const char *path) | ||
1298 | { | ||
1299 | struct sockaddr_un addr; | ||
1300 | int i, r, fd, sock, exitval[2], num_env, addr_len; | ||
1301 | Buffer m; | ||
1302 | char *term; | ||
1303 | extern char **environ; | ||
1304 | u_int flags; | ||
1305 | |||
1306 | if (mux_command == 0) | ||
1307 | mux_command = SSHMUX_COMMAND_OPEN; | ||
1308 | |||
1309 | switch (options.control_master) { | ||
1310 | case SSHCTL_MASTER_AUTO: | ||
1311 | case SSHCTL_MASTER_AUTO_ASK: | ||
1312 | debug("auto-mux: Trying existing master"); | ||
1313 | /* FALLTHROUGH */ | ||
1314 | case SSHCTL_MASTER_NO: | ||
1315 | break; | ||
1316 | default: | ||
1317 | return; | ||
1318 | } | ||
1319 | |||
1320 | memset(&addr, '\0', sizeof(addr)); | ||
1321 | addr.sun_family = AF_UNIX; | ||
1322 | addr_len = offsetof(struct sockaddr_un, sun_path) + | ||
1323 | strlen(path) + 1; | ||
1324 | |||
1325 | if (strlcpy(addr.sun_path, path, | ||
1326 | sizeof(addr.sun_path)) >= sizeof(addr.sun_path)) | ||
1327 | fatal("ControlPath too long"); | ||
1328 | |||
1329 | if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) | ||
1330 | fatal("%s socket(): %s", __func__, strerror(errno)); | ||
1331 | |||
1332 | if (connect(sock, (struct sockaddr *)&addr, addr_len) == -1) { | ||
1333 | if (mux_command != SSHMUX_COMMAND_OPEN) { | ||
1334 | fatal("Control socket connect(%.100s): %s", path, | ||
1335 | strerror(errno)); | ||
1336 | } | ||
1337 | if (errno == ENOENT) | ||
1338 | debug("Control socket \"%.100s\" does not exist", path); | ||
1339 | else { | ||
1340 | error("Control socket connect(%.100s): %s", path, | ||
1341 | strerror(errno)); | ||
1342 | } | ||
1343 | close(sock); | ||
1344 | return; | ||
1345 | } | ||
1346 | |||
1347 | if (stdin_null_flag) { | ||
1348 | if ((fd = open(_PATH_DEVNULL, O_RDONLY)) == -1) | ||
1349 | fatal("open(/dev/null): %s", strerror(errno)); | ||
1350 | if (dup2(fd, STDIN_FILENO) == -1) | ||
1351 | fatal("dup2: %s", strerror(errno)); | ||
1352 | if (fd > STDERR_FILENO) | ||
1353 | close(fd); | ||
1354 | } | ||
1355 | |||
1356 | term = getenv("TERM"); | ||
1357 | |||
1358 | flags = 0; | ||
1359 | if (tty_flag) | ||
1360 | flags |= SSHMUX_FLAG_TTY; | ||
1361 | if (subsystem_flag) | ||
1362 | flags |= SSHMUX_FLAG_SUBSYS; | ||
1363 | if (options.forward_x11) | ||
1364 | flags |= SSHMUX_FLAG_X11_FWD; | ||
1365 | if (options.forward_agent) | ||
1366 | flags |= SSHMUX_FLAG_AGENT_FWD; | ||
1367 | |||
1368 | buffer_init(&m); | ||
1369 | |||
1370 | /* Send our command to server */ | ||
1371 | buffer_put_int(&m, mux_command); | ||
1372 | buffer_put_int(&m, flags); | ||
1373 | if (ssh_msg_send(sock, SSHMUX_VER, &m) == -1) | ||
1374 | fatal("%s: msg_send", __func__); | ||
1375 | buffer_clear(&m); | ||
1376 | |||
1377 | /* Get authorisation status and PID of controlee */ | ||
1378 | if (ssh_msg_recv(sock, &m) == -1) | ||
1379 | fatal("%s: msg_recv", __func__); | ||
1380 | if (buffer_get_char(&m) != SSHMUX_VER) | ||
1381 | fatal("%s: wrong version", __func__); | ||
1382 | if (buffer_get_int(&m) != 1) | ||
1383 | fatal("Connection to master denied"); | ||
1384 | control_server_pid = buffer_get_int(&m); | ||
1385 | |||
1386 | buffer_clear(&m); | ||
1387 | |||
1388 | switch (mux_command) { | ||
1389 | case SSHMUX_COMMAND_ALIVE_CHECK: | ||
1390 | fprintf(stderr, "Master running (pid=%d)\r\n", | ||
1391 | control_server_pid); | ||
1392 | exit(0); | ||
1393 | case SSHMUX_COMMAND_TERMINATE: | ||
1394 | fprintf(stderr, "Exit request sent.\r\n"); | ||
1395 | exit(0); | ||
1396 | case SSHMUX_COMMAND_OPEN: | ||
1397 | /* continue below */ | ||
1398 | break; | ||
1399 | default: | ||
1400 | fatal("silly mux_command %d", mux_command); | ||
1401 | } | ||
1402 | |||
1403 | /* SSHMUX_COMMAND_OPEN */ | ||
1404 | buffer_put_cstring(&m, term ? term : ""); | ||
1405 | buffer_append(&command, "\0", 1); | ||
1406 | buffer_put_cstring(&m, buffer_ptr(&command)); | ||
1407 | |||
1408 | if (options.num_send_env == 0 || environ == NULL) { | ||
1409 | buffer_put_int(&m, 0); | ||
1410 | } else { | ||
1411 | /* Pass environment */ | ||
1412 | num_env = 0; | ||
1413 | for (i = 0; environ[i] != NULL; i++) | ||
1414 | if (env_permitted(environ[i])) | ||
1415 | num_env++; /* Count */ | ||
1416 | |||
1417 | buffer_put_int(&m, num_env); | ||
1418 | |||
1419 | for (i = 0; environ[i] != NULL && num_env >= 0; i++) | ||
1420 | if (env_permitted(environ[i])) { | ||
1421 | num_env--; | ||
1422 | buffer_put_cstring(&m, environ[i]); | ||
1423 | } | ||
1424 | } | ||
1425 | |||
1426 | if (ssh_msg_send(sock, SSHMUX_VER, &m) == -1) | ||
1427 | fatal("%s: msg_send", __func__); | ||
1428 | |||
1429 | mm_send_fd(sock, STDIN_FILENO); | ||
1430 | mm_send_fd(sock, STDOUT_FILENO); | ||
1431 | mm_send_fd(sock, STDERR_FILENO); | ||
1432 | |||
1433 | /* Wait for reply, so master has a chance to gather ttymodes */ | ||
1434 | buffer_clear(&m); | ||
1435 | if (ssh_msg_recv(sock, &m) == -1) | ||
1436 | fatal("%s: msg_recv", __func__); | ||
1437 | if (buffer_get_char(&m) != SSHMUX_VER) | ||
1438 | fatal("%s: wrong version", __func__); | ||
1439 | buffer_free(&m); | ||
1440 | |||
1441 | signal(SIGHUP, control_client_sighandler); | ||
1442 | signal(SIGINT, control_client_sighandler); | ||
1443 | signal(SIGTERM, control_client_sighandler); | ||
1444 | signal(SIGWINCH, control_client_sigrelay); | ||
1445 | |||
1446 | if (tty_flag) | ||
1447 | enter_raw_mode(); | ||
1448 | |||
1449 | /* | ||
1450 | * Stick around until the controlee closes the client_fd. | ||
1451 | * Before it does, it is expected to write this process' exit | ||
1452 | * value (one int). This process must read the value and wait for | ||
1453 | * the closure of the client_fd; if this one closes early, the | ||
1454 | * multiplex master will terminate early too (possibly losing data). | ||
1455 | */ | ||
1456 | exitval[0] = 0; | ||
1457 | for (i = 0; !control_client_terminate && i < (int)sizeof(exitval);) { | ||
1458 | r = read(sock, (char *)exitval + i, sizeof(exitval) - i); | ||
1459 | if (r == 0) { | ||
1460 | debug2("Received EOF from master"); | ||
1461 | break; | ||
1462 | } | ||
1463 | if (r == -1) { | ||
1464 | if (errno == EINTR) | ||
1465 | continue; | ||
1466 | fatal("%s: read %s", __func__, strerror(errno)); | ||
1467 | } | ||
1468 | i += r; | ||
1469 | } | ||
1470 | |||
1471 | close(sock); | ||
1472 | leave_raw_mode(); | ||
1473 | if (i > (int)sizeof(int)) | ||
1474 | fatal("%s: master returned too much data (%d > %lu)", | ||
1475 | __func__, i, sizeof(int)); | ||
1476 | if (control_client_terminate) { | ||
1477 | debug2("Exiting on signal %d", control_client_terminate); | ||
1478 | exitval[0] = 255; | ||
1479 | } else if (i < (int)sizeof(int)) { | ||
1480 | debug2("Control master terminated unexpectedly"); | ||
1481 | exitval[0] = 255; | ||
1482 | } else | ||
1483 | debug2("Received exit status from master %d", exitval[0]); | ||
1484 | |||
1485 | if (tty_flag && options.log_level != SYSLOG_LEVEL_QUIET) | ||
1486 | fprintf(stderr, "Shared connection to %s closed.\r\n", host); | ||
1487 | |||
1488 | exit(exitval[0]); | ||
1489 | } | 1288 | } |