]> andersk Git - openssh.git/blobdiff - sshconnect.c
20010115
[openssh.git] / sshconnect.c
index 40e359ceba11ed0fc6a40db389757f08e1cc4e8c..59b273a9c92f48bc65a223c4b5de94ea3916e37e 100644 (file)
@@ -2,13 +2,18 @@
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
  *                    All rights reserved
- * Created: Sat Mar 18 22:15:47 1995 ylo
  * Code to connect to a remote host, and to perform the client side of the
  * login (authentication) dialog.
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: sshconnect.c,v 1.73 2000/05/17 08:20:15 markus Exp $");
+RCSID("$OpenBSD: sshconnect.c,v 1.89 2001/01/04 22:41:03 markus Exp $");
 
 #include <openssl/bn.h>
 #include <openssl/dsa.h>
@@ -30,11 +35,7 @@ char *client_version_string = NULL;
 char *server_version_string = NULL;
 
 extern Options options;
-#ifdef HAVE___PROGNAME
 extern char *__progname;
-#else /* HAVE___PROGNAME */
-static const char *__progname = "ssh";
-#endif /* HAVE___PROGNAME */
 
 /*
  * Connect to the given ssh server using a proxy command.
@@ -108,15 +109,15 @@ ssh_proxy_connect(const char *host, u_short port, uid_t original_real_uid,
 
                /* Stderr is left as it is so that error messages get
                   printed on the user's terminal. */
-               argv[0] = "/bin/sh";
+               argv[0] = _PATH_BSHELL;
                argv[1] = "-c";
                argv[2] = command_string;
                argv[3] = NULL;
 
                /* Execute the proxy command.  Note that we gave up any
                   extra privileges above. */
-               execv("/bin/sh", argv);
-               perror("/bin/sh");
+               execv(argv[0], argv);
+               perror(argv[0]);
                exit(1);
        }
        /* Parent. */
@@ -193,8 +194,8 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
        int gaierr;
        struct linger linger;
 
-       debug("ssh_connect: getuid %d geteuid %d anon %d",
-             (int) getuid(), (int) geteuid(), anonymous);
+       debug("ssh_connect: getuid %u geteuid %u anon %d",
+             (u_int) getuid(), (u_int) geteuid(), anonymous);
 
        /* Get default port if port has not been set. */
        if (port == 0) {
@@ -243,7 +244,11 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
 
                        /* Create a socket for connecting. */
                        sock = ssh_create_socket(original_real_uid,
-                           !anonymous && geteuid() == 0 && port < IPPORT_RESERVED,
+#ifdef HAVE_CYGWIN
+                           !anonymous,
+#else
+                           !anonymous && geteuid() == 0,
+#endif
                            ai->ai_family);
                        if (sock < 0)
                                continue;
@@ -312,25 +317,31 @@ ssh_exchange_identification()
        int remote_major, remote_minor, i, mismatch;
        int connection_in = packet_get_connection_in();
        int connection_out = packet_get_connection_out();
+       int minor1 = PROTOCOL_MINOR_1; 
 
        /* Read other side\'s version identification. */
-       for (i = 0; i < sizeof(buf) - 1; i++) {
-               int len = read(connection_in, &buf[i], 1);
-               if (len < 0)
-                       fatal("ssh_exchange_identification: read: %.100s", strerror(errno));
-               if (len != 1)
-                       fatal("ssh_exchange_identification: Connection closed by remote host");
-               if (buf[i] == '\r') {
-                       buf[i] = '\n';
-                       buf[i + 1] = 0;
-                       continue;               /**XXX wait for \n */
+       for (;;) {
+               for (i = 0; i < sizeof(buf) - 1; i++) {
+                       int len = atomicio(read, connection_in, &buf[i], 1);
+                       if (len < 0)
+                               fatal("ssh_exchange_identification: read: %.100s", strerror(errno));
+                       if (len != 1)
+                               fatal("ssh_exchange_identification: Connection closed by remote host");
+                       if (buf[i] == '\r') {
+                               buf[i] = '\n';
+                               buf[i + 1] = 0;
+                               continue;               /**XXX wait for \n */
+                       }
+                       if (buf[i] == '\n') {
+                               buf[i + 1] = 0;
+                               break;
+                       }
                }
-               if (buf[i] == '\n') {
-                       buf[i + 1] = 0;
+               buf[sizeof(buf) - 1] = 0;
+               if (strncmp(buf, "SSH-", 4) == 0)
                        break;
-               }
+               debug("ssh_exchange_identification: %s", buf);
        }
-       buf[sizeof(buf) - 1] = 0;
        server_version_string = xstrdup(buf);
 
        /*
@@ -360,9 +371,10 @@ ssh_exchange_identification()
                }
                if (remote_minor < 3) {
                        fatal("Remote machine has too old SSH software version.");
-               } else if (remote_minor == 3) {
+               } else if (remote_minor == 3 || remote_minor == 4) {
                        /* We speak 1.3, too. */
                        enable_compat13();
+                       minor1 = 3;
                        if (options.forward_agent) {
                                log("Agent forwarding disabled for protocol 1.3");
                                options.forward_agent = 0;
@@ -388,7 +400,7 @@ ssh_exchange_identification()
        /* Send our own protocol version identification. */
        snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n",
            compat20 ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1,
-           compat20 ? PROTOCOL_MINOR_2 : PROTOCOL_MINOR_1,
+           compat20 ? PROTOCOL_MINOR_2 : minor1,
            SSH_VERSION);
        if (atomicio(write, connection_out, buf, strlen(buf)) != strlen(buf))
                fatal("write: %.100s", strerror(errno));
@@ -405,7 +417,7 @@ read_yes_or_no(const char *prompt, int defval)
        FILE *f;
        int retval = -1;
 
-       if (isatty(0))
+       if (isatty(STDIN_FILENO))
                f = stdin;
        else
                f = fopen("/dev/tty", "rw");
@@ -430,8 +442,10 @@ read_yes_or_no(const char *prompt, int defval)
                        retval = defval;
                if (strcmp(buf, "yes") == 0)
                        retval = 1;
-               if (strcmp(buf, "no") == 0)
+               else if (strcmp(buf, "no") == 0)
                        retval = 0;
+               else
+                       fprintf(stderr, "Please type 'yes' or 'no'.\n");
 
                if (retval != -1) {
                        if (f != stdin)
@@ -458,6 +472,8 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
        int local = 0, host_ip_differ = 0;
        int salen;
        char ntop[NI_MAXHOST];
+       int host_line, ip_line;
+       const char *host_file = NULL, *ip_file = NULL;
 
        /*
         * Force accepting of the host key for loopback/localhost. The
@@ -482,23 +498,40 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
                salen = sizeof(struct sockaddr_storage);
                break;
        }
-       if (local) {
-               debug("Forcing accepting of host key for loopback/localhost.");
+       if (local && options.host_key_alias == NULL) {
+               debug("Forcing accepting of host key for "
+                   "loopback/localhost.");
                return;
        }
 
        /*
-        * Turn off check_host_ip for proxy connects, since
-        * we don't have the remote ip-address
+        * We don't have the remote ip-address for connections
+        * using a proxy command
         */
-       if (options.proxy_command != NULL && options.check_host_ip)
-               options.check_host_ip = 0;
-
-       if (options.check_host_ip) {
+       if (options.proxy_command == NULL) {
                if (getnameinfo(hostaddr, salen, ntop, sizeof(ntop),
                    NULL, 0, NI_NUMERICHOST) != 0)
                        fatal("check_host_key: getnameinfo failed");
                ip = xstrdup(ntop);
+       } else {
+               ip = xstrdup("<no hostip for proxy command>");
+       }
+       /*
+        * Turn off check_host_ip if the connection is to localhost, via proxy
+        * command or if we don't have a hostname to compare with
+        */
+       if (options.check_host_ip &&
+           (local || strcmp(host, ip) == 0 || options.proxy_command != NULL))
+               options.check_host_ip = 0;
+
+       /*
+        * Allow the user to record the key under a different name. This is
+        * useful for ssh tunneling over forwarded connections or if you run
+        * multiple sshd's on different ports on the same machine.
+        */
+       if (options.host_key_alias != NULL) {
+               host = options.host_key_alias;
+               debug("using hostkeyalias: %s", host);
        }
 
        /*
@@ -511,19 +544,25 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
         * Check if the host key is present in the user\'s list of known
         * hosts or in the systemwide list.
         */
-       host_status = check_host_in_hostfile(user_hostfile, host, host_key, file_key);
-       if (host_status == HOST_NEW)
-               host_status = check_host_in_hostfile(system_hostfile, host, host_key, file_key);
+       host_file = user_hostfile;
+       host_status = check_host_in_hostfile(host_file, host, host_key, file_key, &host_line);
+       if (host_status == HOST_NEW) {
+               host_file = system_hostfile;
+               host_status = check_host_in_hostfile(host_file, host, host_key, file_key, &host_line);
+       }
        /*
         * Also perform check for the ip address, skip the check if we are
         * localhost or the hostname was an ip address to begin with
         */
-       if (options.check_host_ip && !local && strcmp(host, ip)) {
+       if (options.check_host_ip) {
                Key *ip_key = key_new(host_key->type);
-               ip_status = check_host_in_hostfile(user_hostfile, ip, host_key, ip_key);
 
-               if (ip_status == HOST_NEW)
-                       ip_status = check_host_in_hostfile(system_hostfile, ip, host_key, ip_key);
+               ip_file = user_hostfile;
+               ip_status = check_host_in_hostfile(ip_file, ip, host_key, ip_key, &ip_line);
+               if (ip_status == HOST_NEW) {
+                       ip_file = system_hostfile;
+                       ip_status = check_host_in_hostfile(ip_file, ip, host_key, ip_key, &ip_line);
+               }
                if (host_status == HOST_CHANGED &&
                    (ip_status != HOST_CHANGED || !key_equal(ip_key, file_key)))
                        host_ip_differ = 1;
@@ -539,17 +578,14 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
                /* The host is known and the key matches. */
                debug("Host '%.200s' is known and matches the %s host key.",
                    host, type);
-               if (options.check_host_ip) {
-                       if (ip_status == HOST_NEW) {
-                               if (!add_host_to_hostfile(user_hostfile, ip, host_key))
-                                       log("Failed to add the %s host key for IP address '%.30s' to the list of known hosts (%.30s).",
-                                           type, ip, user_hostfile);
-                               else
-                                       log("Warning: Permanently added the %s host key for IP address '%.30s' to the list of known hosts.",
-                                           type, ip);
-                       } else if (ip_status != HOST_OK)
-                               log("Warning: the %s host key for '%.200s' differs from the key for the IP address '%.30s'",
-                                   type, host, ip);
+               debug("Found key in %s:%d", host_file, host_line);
+               if (options.check_host_ip && ip_status == HOST_NEW) {
+                       if (!add_host_to_hostfile(user_hostfile, ip, host_key))
+                               log("Failed to add the %s host key for IP address '%.30s' to the list of known hosts (%.30s).",
+                                   type, ip, user_hostfile);
+                       else
+                               log("Warning: Permanently added the %s host key for IP address '%.30s' to the list of known hosts.",
+                                   type, ip);
                }
                break;
        case HOST_NEW:
@@ -561,16 +597,15 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
                } else if (options.strict_host_key_checking == 2) {
                        /* The default */
                        char prompt[1024];
-                       char *fp = key_fingerprint(host_key);
                        snprintf(prompt, sizeof(prompt),
-                           "The authenticity of host '%.200s' can't be established.\n"
+                           "The authenticity of host '%.200s (%s)' can't be established.\n"
                            "%s key fingerprint is %s.\n"
                            "Are you sure you want to continue connecting (yes/no)? ",
-                           host, type, fp);
+                           host, ip, type, key_fingerprint(host_key));
                        if (!read_yes_or_no(prompt, -1))
                                fatal("Aborted by user!\n");
                }
-               if (options.check_host_ip && ip_status == HOST_NEW && strcmp(host, ip)) {
+               if (options.check_host_ip && ip_status == HOST_NEW) {
                        snprintf(hostline, sizeof(hostline), "%s,%s", host, ip);
                        hostp = hostline;
                } else
@@ -600,7 +635,9 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
                        error("and the key for the according IP address %s", ip);
                        error("%s. This could either mean that", msg);
                        error("DNS SPOOFING is happening or the IP address for the host");
-                       error("and its host key have changed at the same time");
+                       error("and its host key have changed at the same time.");
+                       if (ip_status != HOST_NEW)
+                               error("Offending key for IP in %s:%d", ip_file, ip_line);
                }
                /* The host key has changed. */
                error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
@@ -609,9 +646,12 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
                error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!");
                error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!");
                error("It is also possible that the %s host key has just been changed.", type);
+               error("The fingerprint for the %s key sent by the remote host is\n%s.",
+                   type, key_fingerprint(host_key));
                error("Please contact your system administrator.");
                error("Add correct host key in %.100s to get rid of this message.",
-                     user_hostfile);
+                   user_hostfile);
+               error("Offending key in %s:%d", host_file, host_line);
 
                /*
                 * If strict host key checking is in use, the user will have
@@ -633,6 +673,14 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
                        error("Agent forwarding is disabled to avoid trojan horses.");
                        options.forward_agent = 0;
                }
+               if (options.forward_x11) {
+                       error("X11 forwarding is disabled to avoid trojan horses.");
+                       options.forward_x11 = 0;
+               }
+               if (options.num_local_forwards > 0 || options.num_remote_forwards > 0) {
+                       error("Port forwarding is disabled to avoid trojan horses.");
+                       options.num_local_forwards = options.num_remote_forwards = 0;
+               }
                /*
                 * XXX Should permit the user to change to use the new id.
                 * This could be done by converting the host key to an
@@ -642,8 +690,24 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
                 */
                break;
        }
-       if (options.check_host_ip)
-               xfree(ip);
+
+       if (options.check_host_ip && host_status != HOST_CHANGED &&
+           ip_status == HOST_CHANGED) {
+               log("Warning: the %s host key for '%.200s' "
+                   "differs from the key for the IP address '%.30s'",
+                   type, host, ip);
+               if (host_status == HOST_OK)
+                       log("Matching host key in %s:%d", host_file, host_line);
+               log("Offending key for IP in %s:%d", ip_file, ip_line);
+               if (options.strict_host_key_checking == 1) {
+                       fatal("Exiting, you have requested strict checking.");
+               } else if (options.strict_host_key_checking == 2) {
+                       if (!read_yes_or_no("Continue?", -1))
+                               fatal("Aborted by user!\n");
+               }
+       }
+
+       xfree(ip);
 }
 
 /*
@@ -664,7 +728,7 @@ ssh_login(int host_key_valid, RSA *own_host_key, const char *orighost,
        /* Get local user name.  Use it as server user if no user name was given. */
        pw = getpwuid(original_real_uid);
        if (!pw)
-               fatal("User id %d not found from user database.", original_real_uid);
+               fatal("User id %u not found from user database.", original_real_uid);
        local_user = xstrdup(pw->pw_name);
        server_user = options.user ? options.user : local_user;
 
This page took 0.268733 seconds and 4 git commands to generate.