-/* $OpenBSD: ssh.c,v 1.298 2007/06/12 11:45:27 djm Exp $ */
+/* $OpenBSD: ssh.c,v 1.303 2007/09/04 11:15:55 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
char *p, *cp, *line, buf[256];
struct stat st;
struct passwd *pw;
- int dummy;
+ int dummy, timeout_ms;
extern int optind, optreset;
extern char *optarg;
struct servent *sp;
if (options.control_path != NULL)
control_client(options.control_path);
+ timeout_ms = options.connection_timeout * 1000;
+
/* Open a connection to the remote host. */
if (ssh_connect(host, &hostaddr, options.port,
- options.address_family, options.connection_attempts,
+ options.address_family, options.connection_attempts, &timeout_ms,
+ options.tcp_keep_alive,
#ifdef HAVE_CYGWIN
options.use_privileged_port,
#else
options.proxy_command) != 0)
exit(255);
+ if (timeout_ms > 0)
+ debug3("timeout: %d ms remain after connect", timeout_ms);
+
/*
* If we successfully made the connection, load the host private key
* in case we will need it later for combined rsa-rhosts
signal(SIGPIPE, SIG_IGN); /* ignore SIGPIPE early */
/* Log into the remote system. This never returns if the login fails. */
- ssh_login(&sensitive_data, host, (struct sockaddr *)&hostaddr, pw);
+ ssh_login(&sensitive_data, host, (struct sockaddr *)&hostaddr,
+ pw, timeout_ms);
/* We no longer need the private host keys. Clear them now. */
if (sensitive_data.nkeys != 0) {
"forwarding.");
}
}
+
+ /* Initiate tunnel forwarding. */
+ if (options.tun_open != SSH_TUNMODE_NO) {
+ if (client_request_tun_fwd(options.tun_open,
+ options.tun_local, options.tun_remote) == -1) {
+ if (options.exit_on_forward_failure)
+ fatal("Could not request tunnel forwarding.");
+ else
+ error("Could not request tunnel forwarding.");
+ }
+ }
}
static void
packet_send();
}
- if (options.tun_open != SSH_TUNMODE_NO) {
- Channel *c;
- int fd;
-
- debug("Requesting tun.");
- if ((fd = tun_open(options.tun_local,
- options.tun_open)) >= 0) {
- c = channel_new("tun", SSH_CHANNEL_OPENING, fd, fd, -1,
- CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT,
- 0, "tun", 1);
- c->datagram = 1;
-#if defined(SSH_TUN_FILTER)
- if (options.tun_open == SSH_TUNMODE_POINTOPOINT)
- channel_register_filter(c->self, sys_tun_infilter,
- sys_tun_outfilter);
-#endif
- packet_start(SSH2_MSG_CHANNEL_OPEN);
- packet_put_cstring("tun@openssh.com");
- packet_put_int(c->self);
- packet_put_int(c->local_window_max);
- packet_put_int(c->local_maxpacket);
- packet_put_int(options.tun_open);
- packet_put_int(options.tun_remote);
- packet_send();
- }
- }
-
client_session2_setup(id, tty_flag, subsystem_flag, getenv("TERM"),
NULL, fileno(stdin), &command, environ, &ssh_subsystem_reply);
/* XXX should be pre-session */
ssh_init_forwarding();
- ssh_control_listener();
if (!no_shell_flag || (datafellows & SSH_BUG_DUMMYCHAN))
id = ssh_session2_open();
options.permit_local_command)
ssh_local_cmd(options.local_command);
+ /* Start listening for multiplex clients */
+ ssh_control_listener();
+
/* If requested, let ssh continue in the background. */
if (fork_after_authentication_flag)
if (daemon(1, 1) < 0)
control_client(const char *path)
{
struct sockaddr_un addr;
- int i, r, fd, sock, exitval, num_env, addr_len;
+ int i, r, fd, sock, exitval[2], num_env, addr_len;
Buffer m;
char *term;
extern char **environ;
if (ssh_msg_send(sock, SSHMUX_VER, &m) == -1)
fatal("%s: msg_send", __func__);
- mm_send_fd(sock, STDIN_FILENO);
- mm_send_fd(sock, STDOUT_FILENO);
- mm_send_fd(sock, STDERR_FILENO);
+ if (mm_send_fd(sock, STDIN_FILENO) == -1 ||
+ mm_send_fd(sock, STDOUT_FILENO) == -1 ||
+ mm_send_fd(sock, STDERR_FILENO) == -1)
+ fatal("%s: send fds failed", __func__);
/* Wait for reply, so master has a chance to gather ttymodes */
buffer_clear(&m);
if (tty_flag)
enter_raw_mode();
- /* Stick around until the controlee closes the client_fd */
- exitval = 0;
+ /*
+ * Stick around until the controlee closes the client_fd.
+ * Before it does, it is expected to write this process' exit
+ * value (one int). This process must read the value and wait for
+ * the closure of the client_fd; if this one closes early, the
+ * multiplex master will terminate early too (possibly losing data).
+ */
+ exitval[0] = 0;
for (i = 0; !control_client_terminate && i < (int)sizeof(exitval);) {
- r = read(sock, (char *)&exitval + i, sizeof(exitval) - i);
+ r = read(sock, (char *)exitval + i, sizeof(exitval) - i);
if (r == 0) {
debug2("Received EOF from master");
break;
}
- if (r == -1 && errno != EINTR)
+ if (r == -1) {
+ if (errno == EINTR)
+ continue;
fatal("%s: read %s", __func__, strerror(errno));
+ }
i += r;
}
+
close(sock);
leave_raw_mode();
-
+ if (i > (int)sizeof(int))
+ fatal("%s: master returned too much data (%d > %lu)",
+ __func__, i, sizeof(int));
if (control_client_terminate) {
debug2("Exiting on signal %d", control_client_terminate);
- exitval = 255;
- } else if (i < (int)sizeof(exitval)) {
+ exitval[0] = 255;
+ } else if (i < (int)sizeof(int)) {
debug2("Control master terminated unexpectedly");
- exitval = 255;
+ exitval[0] = 255;
} else
- debug2("Received exit status from master %d", exitval);
+ debug2("Received exit status from master %d", exitval[0]);
if (tty_flag && options.log_level != SYSLOG_LEVEL_QUIET)
- fprintf(stderr, "Shared connection to %s closed.\r\n",
- host);
+ fprintf(stderr, "Shared connection to %s closed.\r\n", host);
- exit(exitval);
+ exit(exitval[0]);
}