summaryrefslogtreecommitdiffstats
path: root/sshconnect.c
diff options
context:
space:
mode:
authordes <des@FreeBSD.org>2014-01-30 10:56:49 +0000
committerdes <des@FreeBSD.org>2014-01-30 10:56:49 +0000
commit45d0197dd79eceffb5bbc29f75199eb09af5a5f9 (patch)
tree6c519c109631364b652faced88b665da4b6058ae /sshconnect.c
parent31fac2f7108f657f455d571b94ed1a5c86d075b2 (diff)
downloadFreeBSD-src-45d0197dd79eceffb5bbc29f75199eb09af5a5f9.zip
FreeBSD-src-45d0197dd79eceffb5bbc29f75199eb09af5a5f9.tar.gz
Vendor import of OpenSSH 6.5p1.
Diffstat (limited to 'sshconnect.c')
-rw-r--r--sshconnect.c248
1 files changed, 167 insertions, 81 deletions
diff --git a/sshconnect.c b/sshconnect.c
index 483eb85..d21781e 100644
--- a/sshconnect.c
+++ b/sshconnect.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshconnect.c,v 1.238 2013/05/17 00:13:14 djm Exp $ */
+/* $OpenBSD: sshconnect.c,v 1.244 2014/01/09 23:26:48 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -59,6 +59,7 @@
#include "misc.h"
#include "dns.h"
#include "roaming.h"
+#include "monitor_fdpass.h"
#include "ssh2.h"
#include "version.h"
@@ -78,47 +79,122 @@ extern uid_t original_effective_uid;
static int show_other_keys(struct hostkeys *, Key *);
static void warn_changed_key(Key *);
+/* Expand a proxy command */
+static char *
+expand_proxy_command(const char *proxy_command, const char *user,
+ const char *host, int port)
+{
+ char *tmp, *ret, strport[NI_MAXSERV];
+
+ snprintf(strport, sizeof strport, "%d", port);
+ xasprintf(&tmp, "exec %s", proxy_command);
+ ret = percent_expand(tmp, "h", host, "p", strport,
+ "r", options.user, (char *)NULL);
+ free(tmp);
+ return ret;
+}
+
+/*
+ * Connect to the given ssh server using a proxy command that passes a
+ * a connected fd back to us.
+ */
+static int
+ssh_proxy_fdpass_connect(const char *host, u_short port,
+ const char *proxy_command)
+{
+ char *command_string;
+ int sp[2], sock;
+ pid_t pid;
+ char *shell;
+
+ if ((shell = getenv("SHELL")) == NULL)
+ shell = _PATH_BSHELL;
+
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, sp) < 0)
+ fatal("Could not create socketpair to communicate with "
+ "proxy dialer: %.100s", strerror(errno));
+
+ command_string = expand_proxy_command(proxy_command, options.user,
+ host, port);
+ debug("Executing proxy dialer command: %.500s", command_string);
+
+ /* Fork and execute the proxy command. */
+ if ((pid = fork()) == 0) {
+ char *argv[10];
+
+ /* Child. Permanently give up superuser privileges. */
+ permanently_drop_suid(original_real_uid);
+
+ close(sp[1]);
+ /* Redirect stdin and stdout. */
+ if (sp[0] != 0) {
+ if (dup2(sp[0], 0) < 0)
+ perror("dup2 stdin");
+ }
+ if (sp[0] != 1) {
+ if (dup2(sp[0], 1) < 0)
+ perror("dup2 stdout");
+ }
+ if (sp[0] >= 2)
+ close(sp[0]);
+
+ /*
+ * Stderr is left as it is so that error messages get
+ * printed on the user's terminal.
+ */
+ argv[0] = shell;
+ argv[1] = "-c";
+ argv[2] = command_string;
+ argv[3] = NULL;
+
+ /*
+ * Execute the proxy command.
+ * Note that we gave up any extra privileges above.
+ */
+ execv(argv[0], argv);
+ perror(argv[0]);
+ exit(1);
+ }
+ /* Parent. */
+ if (pid < 0)
+ fatal("fork failed: %.100s", strerror(errno));
+ close(sp[0]);
+ free(command_string);
+
+ if ((sock = mm_receive_fd(sp[1])) == -1)
+ fatal("proxy dialer did not pass back a connection");
+
+ while (waitpid(pid, NULL, 0) == -1)
+ if (errno != EINTR)
+ fatal("Couldn't wait for child: %s", strerror(errno));
+
+ /* Set the connection file descriptors. */
+ packet_set_connection(sock, sock);
+
+ return 0;
+}
+
/*
* Connect to the given ssh server using a proxy command.
*/
static int
ssh_proxy_connect(const char *host, u_short port, const char *proxy_command)
{
- char *command_string, *tmp;
+ char *command_string;
int pin[2], pout[2];
pid_t pid;
- char *shell, strport[NI_MAXSERV];
-
- if (!strcmp(proxy_command, "-")) {
- packet_set_connection(STDIN_FILENO, STDOUT_FILENO);
- packet_set_timeout(options.server_alive_interval,
- options.server_alive_count_max);
- return 0;
- }
+ char *shell;
if ((shell = getenv("SHELL")) == NULL || *shell == '\0')
shell = _PATH_BSHELL;
- /* Convert the port number into a string. */
- snprintf(strport, sizeof strport, "%hu", port);
-
- /*
- * Build the final command string in the buffer by making the
- * appropriate substitutions to the given proxy command.
- *
- * Use "exec" to avoid "sh -c" processes on some platforms
- * (e.g. Solaris)
- */
- xasprintf(&tmp, "exec %s", proxy_command);
- command_string = percent_expand(tmp, "h", host, "p", strport,
- "r", options.user, (char *)NULL);
- free(tmp);
-
/* Create pipes for communicating with the proxy. */
if (pipe(pin) < 0 || pipe(pout) < 0)
fatal("Could not create pipes to communicate with the proxy: %.100s",
strerror(errno));
+ command_string = expand_proxy_command(proxy_command, options.user,
+ host, port);
debug("Executing proxy command: %.500s", command_string);
/* Fork and execute the proxy command. */
@@ -170,8 +246,6 @@ ssh_proxy_connect(const char *host, u_short port, const char *proxy_command)
/* Set the connection file descriptors. */
packet_set_connection(pout[0], pin[1]);
- packet_set_timeout(options.server_alive_interval,
- options.server_alive_count_max);
/* Indicate OK return */
return 0;
@@ -194,34 +268,18 @@ ssh_kill_proxy_command(void)
static int
ssh_create_socket(int privileged, struct addrinfo *ai)
{
- int sock, gaierr;
+ int sock, r, gaierr;
struct addrinfo hints, *res;
- /*
- * If we are running as root and want to connect to a privileged
- * port, bind our own socket to a privileged port.
- */
- if (privileged) {
- int p = IPPORT_RESERVED - 1;
- PRIV_START;
- sock = rresvport_af(&p, ai->ai_family);
- PRIV_END;
- if (sock < 0)
- error("rresvport: af=%d %.100s", ai->ai_family,
- strerror(errno));
- else
- debug("Allocated local port %d.", p);
- return sock;
- }
sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
if (sock < 0) {
- error("socket: %.100s", strerror(errno));
+ error("socket: %s", strerror(errno));
return -1;
}
fcntl(sock, F_SETFD, FD_CLOEXEC);
/* Bind the socket to an alternative local IP address */
- if (options.bind_address == NULL)
+ if (options.bind_address == NULL && !privileged)
return sock;
memset(&hints, 0, sizeof(hints));
@@ -236,11 +294,28 @@ ssh_create_socket(int privileged, struct addrinfo *ai)
close(sock);
return -1;
}
- if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) {
- error("bind: %s: %s", options.bind_address, strerror(errno));
- close(sock);
- freeaddrinfo(res);
- return -1;
+ /*
+ * If we are running as root and want to connect to a privileged
+ * port, bind our own socket to a privileged port.
+ */
+ if (privileged) {
+ PRIV_START;
+ r = bindresvport_sa(sock, res->ai_addr);
+ PRIV_END;
+ if (r < 0) {
+ error("bindresvport_sa: af=%d %s", ai->ai_family,
+ strerror(errno));
+ goto fail;
+ }
+ } else {
+ if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) {
+ error("bind: %s: %s", options.bind_address,
+ strerror(errno));
+ fail:
+ close(sock);
+ freeaddrinfo(res);
+ return -1;
+ }
}
freeaddrinfo(res);
return sock;
@@ -340,33 +415,18 @@ timeout_connect(int sockfd, const struct sockaddr *serv_addr,
* and %p substituted for host and port, respectively) to use to contact
* the daemon.
*/
-int
-ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
- u_short port, int family, int connection_attempts, int *timeout_ms,
- int want_keepalive, int needpriv, const char *proxy_command)
+static int
+ssh_connect_direct(const char *host, struct addrinfo *aitop,
+ struct sockaddr_storage *hostaddr, u_short port, int family,
+ int connection_attempts, int *timeout_ms, int want_keepalive, int needpriv)
{
- int gaierr;
int on = 1;
int sock = -1, attempt;
char ntop[NI_MAXHOST], strport[NI_MAXSERV];
- struct addrinfo hints, *ai, *aitop;
+ struct addrinfo *ai;
debug2("ssh_connect: needpriv %d", needpriv);
- /* If a proxy command is given, connect using it. */
- if (proxy_command != NULL)
- return ssh_proxy_connect(host, port, proxy_command);
-
- /* No proxy command. */
-
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = family;
- hints.ai_socktype = SOCK_STREAM;
- snprintf(strport, sizeof strport, "%u", port);
- if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0)
- fatal("%s: Could not resolve hostname %.100s: %s", __progname,
- host, ssh_gai_strerror(gaierr));
-
for (attempt = 0; attempt < connection_attempts; attempt++) {
if (attempt > 0) {
/* Sleep a moment before retrying. */
@@ -378,7 +438,8 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
* sequence until the connection succeeds.
*/
for (ai = aitop; ai; ai = ai->ai_next) {
- if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
+ if (ai->ai_family != AF_INET &&
+ ai->ai_family != AF_INET6)
continue;
if (getnameinfo(ai->ai_addr, ai->ai_addrlen,
ntop, sizeof(ntop), strport, sizeof(strport),
@@ -411,8 +472,6 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
break; /* Successful connection. */
}
- freeaddrinfo(aitop);
-
/* Return failure if we didn't get a successful connection. */
if (sock == -1) {
error("ssh: connect to host %s port %s: %s",
@@ -430,12 +489,28 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
/* Set the connection. */
packet_set_connection(sock, sock);
- packet_set_timeout(options.server_alive_interval,
- options.server_alive_count_max);
return 0;
}
+int
+ssh_connect(const char *host, struct addrinfo *addrs,
+ struct sockaddr_storage *hostaddr, u_short port, int family,
+ int connection_attempts, int *timeout_ms, int want_keepalive, int needpriv)
+{
+ if (options.proxy_command == NULL) {
+ return ssh_connect_direct(host, addrs, hostaddr, port, family,
+ connection_attempts, timeout_ms, want_keepalive, needpriv);
+ } else if (strcmp(options.proxy_command, "-") == 0) {
+ packet_set_connection(STDIN_FILENO, STDOUT_FILENO);
+ return 0; /* Always succeeds */
+ } else if (options.proxy_use_fdpass) {
+ return ssh_proxy_fdpass_connect(host, port,
+ options.proxy_command);
+ }
+ return ssh_proxy_connect(host, port, options.proxy_command);
+}
+
static void
send_client_banner(int connection_out, int minor1)
{
@@ -587,6 +662,12 @@ ssh_exchange_identification(int timeout_ms)
fatal("Protocol major versions differ: %d vs. %d",
(options.protocol & SSH_PROTO_2) ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1,
remote_major);
+ if ((datafellows & SSH_BUG_DERIVEKEY) != 0)
+ fatal("Server version \"%.100s\" uses unsafe key agreement; "
+ "refusing connection", remote_version);
+ if ((datafellows & SSH_BUG_RSASIGMD5) != 0)
+ logit("Server version \"%.100s\" uses unsafe RSA signature "
+ "scheme; disabling use of RSA keys", remote_version);
if (!client_banner_sent)
send_client_banner(connection_out, minor1);
chop(server_version_string);
@@ -1176,7 +1257,7 @@ void
ssh_login(Sensitive *sensitive, const char *orighost,
struct sockaddr *hostaddr, u_short port, struct passwd *pw, int timeout_ms)
{
- char *host, *cp;
+ char *host;
char *server_user, *local_user;
local_user = xstrdup(pw->pw_name);
@@ -1184,9 +1265,7 @@ ssh_login(Sensitive *sensitive, const char *orighost,
/* Convert the user-supplied hostname into all lowercase. */
host = xstrdup(orighost);
- for (cp = host; *cp; cp++)
- if (isupper(*cp))
- *cp = (char)tolower(*cp);
+ lowercase(host);
/* Exchange protocol version identification strings with the server. */
ssh_exchange_identification(timeout_ms);
@@ -1228,7 +1307,14 @@ ssh_put_password(char *password)
static int
show_other_keys(struct hostkeys *hostkeys, Key *key)
{
- int type[] = { KEY_RSA1, KEY_RSA, KEY_DSA, KEY_ECDSA, -1};
+ int type[] = {
+ KEY_RSA1,
+ KEY_RSA,
+ KEY_DSA,
+ KEY_ECDSA,
+ KEY_ED25519,
+ -1
+ };
int i, ret = 0;
char *fp, *ra;
const struct hostkey_entry *found;
OpenPOWER on IntegriCloud