openssh-5.9p1-xauthlocalhostname.diff
[platform/upstream/openssh.git] / sshconnect.c
index cf07112..573d7a8 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshconnect.c,v 1.237 2013/02/22 19:13:56 markus Exp $ */
+/* $OpenBSD: sshconnect.c,v 1.246 2014/02/06 22:21:01 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);
-       xfree(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. */
@@ -166,12 +242,10 @@ ssh_proxy_connect(const char *host, u_short port, const char *proxy_command)
        close(pout[1]);
 
        /* Free the command name. */
-       xfree(command_string);
+       free(command_string);
 
        /* 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,55 +268,59 @@ ssh_kill_proxy_command(void)
 static int
 ssh_create_socket(int privileged, struct addrinfo *ai)
 {
-       int sock, gaierr;
-       struct addrinfo hints, *res;
+       int sock, r, gaierr;
+       struct addrinfo hints, *res = NULL;
 
-       /*
-        * 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));
-       hints.ai_family = ai->ai_family;
-       hints.ai_socktype = ai->ai_socktype;
-       hints.ai_protocol = ai->ai_protocol;
-       hints.ai_flags = AI_PASSIVE;
-       gaierr = getaddrinfo(options.bind_address, NULL, &hints, &res);
-       if (gaierr) {
-               error("getaddrinfo: %s: %s", options.bind_address,
-                   ssh_gai_strerror(gaierr));
-               close(sock);
-               return -1;
+       if (options.bind_address) {
+               memset(&hints, 0, sizeof(hints));
+               hints.ai_family = ai->ai_family;
+               hints.ai_socktype = ai->ai_socktype;
+               hints.ai_protocol = ai->ai_protocol;
+               hints.ai_flags = AI_PASSIVE;
+               gaierr = getaddrinfo(options.bind_address, NULL, &hints, &res);
+               if (gaierr) {
+                       error("getaddrinfo: %s: %s", options.bind_address,
+                           ssh_gai_strerror(gaierr));
+                       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 ? res->ai_addr : NULL);
+               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);
+       if (res != NULL)
+               freeaddrinfo(res);
        return sock;
 }
 
@@ -315,7 +393,7 @@ timeout_connect(int sockfd, const struct sockaddr *serv_addr,
                fatal("Bogus return (%d) from select()", rc);
        }
 
-       xfree(fdset);
+       free(fdset);
 
  done:
        if (result == 0 && *timeoutp > 0) {
@@ -340,33 +418,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 +441,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 +475,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 +492,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)
 {
@@ -534,7 +612,7 @@ ssh_exchange_identification(int timeout_ms)
                debug("ssh_exchange_identification: %s", buf);
        }
        server_version_string = xstrdup(buf);
-       xfree(fdset);
+       free(fdset);
 
        /*
         * Check that the versions match.  In future this might accept
@@ -587,6 +665,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);
@@ -610,8 +694,7 @@ confirm(const char *prompt)
                        ret = 0;
                if (p && strncasecmp(p, "yes", 3) == 0)
                        ret = 1;
-               if (p)
-                       xfree(p);
+               free(p);
                if (ret != -1)
                        return ret;
        }
@@ -835,8 +918,8 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
                        ra = key_fingerprint(host_key, SSH_FP_MD5,
                            SSH_FP_RANDOMART);
                        logit("Host key fingerprint is %s\n%s\n", fp, ra);
-                       xfree(ra);
-                       xfree(fp);
+                       free(ra);
+                       free(fp);
                }
                break;
        case HOST_NEW:
@@ -896,8 +979,8 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
                            options.visual_host_key ? "\n" : "",
                            options.visual_host_key ? ra : "",
                            msg2);
-                       xfree(ra);
-                       xfree(fp);
+                       free(ra);
+                       free(fp);
                        if (!confirm(msg))
                                goto fail;
                }
@@ -1098,8 +1181,8 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
                }
        }
 
-       xfree(ip);
-       xfree(host);
+       free(ip);
+       free(host);
        if (host_hostkeys != NULL)
                free_hostkeys(host_hostkeys);
        if (ip_hostkeys != NULL)
@@ -1121,8 +1204,8 @@ fail:
        }
        if (raw_key != NULL)
                key_free(raw_key);
-       xfree(ip);
-       xfree(host);
+       free(ip);
+       free(host);
        if (host_hostkeys != NULL)
                free_hostkeys(host_hostkeys);
        if (ip_hostkeys != NULL)
@@ -1139,7 +1222,7 @@ verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
 
        fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
        debug("Server host key: %s %s", key_type(host_key), fp);
-       xfree(fp);
+       free(fp);
 
        /* XXX certs are not yet supported for DNS */
        if (!key_is_cert(host_key) && options.verify_host_key_dns &&
@@ -1177,7 +1260,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);
@@ -1185,9 +1268,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);
@@ -1204,7 +1285,7 @@ ssh_login(Sensitive *sensitive, const char *orighost,
                ssh_kex(host, hostaddr);
                ssh_userauth1(local_user, server_user, host, sensitive);
        }
-       xfree(local_user);
+       free(local_user);
 }
 
 void
@@ -1221,15 +1302,22 @@ ssh_put_password(char *password)
        padded = xcalloc(1, size);
        strlcpy(padded, password, size);
        packet_put_string(padded, size);
-       memset(padded, 0, size);
-       xfree(padded);
+       explicit_bzero(padded, size);
+       free(padded);
 }
 
 /* print all known host keys for a given host, but skip keys of given type */
 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;
@@ -1249,8 +1337,8 @@ show_other_keys(struct hostkeys *hostkeys, Key *key)
                    key_type(found->key), fp);
                if (options.visual_host_key)
                        logit("%s", ra);
-               xfree(ra);
-               xfree(fp);
+               free(ra);
+               free(fp);
                ret = 1;
        }
        return ret;
@@ -1273,7 +1361,7 @@ warn_changed_key(Key *host_key)
            key_type(host_key), fp);
        error("Please contact your system administrator.");
 
-       xfree(fp);
+       free(fp);
 }
 
 /*