[BACK]Return to sshconnect.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Diff for /src/usr.bin/ssh/sshconnect.c between version 1.104 and 1.104.2.1

version 1.104, 2001/04/12 19:15:25 version 1.104.2.1, 2001/09/27 19:03:55
Line 41 
Line 41 
 /* AF_UNSPEC or AF_INET or AF_INET6 */  /* AF_UNSPEC or AF_INET or AF_INET6 */
 extern int IPv4or6;  extern int IPv4or6;
   
   static const char *
   sockaddr_ntop(struct sockaddr *sa)
   {
           void *addr;
           static char addrbuf[INET6_ADDRSTRLEN];
   
           switch (sa->sa_family) {
                   case AF_INET:
                           addr = &((struct sockaddr_in *)sa)->sin_addr;
                           break;
                   case AF_INET6:
                           addr = &((struct sockaddr_in6 *)sa)->sin6_addr;
                           break;
                   default:
                           /* This case should be protected against elsewhere */
                           abort();
           }
           inet_ntop(sa->sa_family, addr, addrbuf, sizeof(addrbuf));
           return addrbuf;
   }
   
 /*  /*
  * Connect to the given ssh server using a proxy command.   * Connect to the given ssh server using a proxy command.
  */   */
 int  static int
 ssh_proxy_connect(const char *host, u_short port, struct passwd *pw,  ssh_proxy_connect(const char *host, u_short port, struct passwd *pw,
                   const char *proxy_command)                    const char *proxy_command)
 {  {
Line 138 
Line 159 
         /* Set the connection file descriptors. */          /* Set the connection file descriptors. */
         packet_set_connection(pout[0], pin[1]);          packet_set_connection(pout[0], pin[1]);
   
         return 1;          /* Indicate OK return */
           return 0;
 }  }
   
 /*  /*
  * Creates a (possibly privileged) socket for use as the ssh connection.   * Creates a (possibly privileged) socket for use as the ssh connection.
  */   */
 int  static int
 ssh_create_socket(struct passwd *pw, int privileged, int family)  ssh_create_socket(struct passwd *pw, int privileged, int family)
 {  {
         int sock;          int sock, gaierr;
           struct addrinfo hints, *res;
   
         /*          /*
          * If we are running as root and want to connect to a privileged           * If we are running as root and want to connect to a privileged
Line 160 
Line 183 
                         error("rresvport: af=%d %.100s", family, strerror(errno));                          error("rresvport: af=%d %.100s", family, strerror(errno));
                 else                  else
                         debug("Allocated local port %d.", p);                          debug("Allocated local port %d.", p);
         } else {                  return sock;
                 /*  
                  * Just create an ordinary socket on arbitrary port.  We use  
                  * the user's uid to create the socket.  
                  */  
                 temporarily_use_uid(pw);  
                 sock = socket(family, SOCK_STREAM, 0);  
                 if (sock < 0)  
                         error("socket: %.100s", strerror(errno));  
                 restore_uid();  
         }          }
           /*
            * Just create an ordinary socket on arbitrary port.  We use
            * the user's uid to create the socket.
            */
           temporarily_use_uid(pw);
           sock = socket(family, SOCK_STREAM, 0);
           if (sock < 0)
                   error("socket: %.100s", strerror(errno));
           restore_uid();
   
           /* Bind the socket to an alternative local IP address */
           if (options.bind_address == NULL)
                   return sock;
   
           memset(&hints, 0, sizeof(hints));
           hints.ai_family = IPv4or6;
           hints.ai_socktype = SOCK_STREAM;
           hints.ai_flags = AI_PASSIVE;
           gaierr = getaddrinfo(options.bind_address, "0", &hints, &res);
           if (gaierr) {
                   error("getaddrinfo: %s: %s", options.bind_address,
                       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;
           }
           freeaddrinfo(res);
         return sock;          return sock;
 }  }
   
Line 184 
Line 230 
  * second).  If proxy_command is non-NULL, it specifies the command (with %h   * second).  If proxy_command is non-NULL, it specifies the command (with %h
  * and %p substituted for host and port, respectively) to use to contact   * and %p substituted for host and port, respectively) to use to contact
  * the daemon.   * the daemon.
    * Return values:
    *    0 for OK
    *    ECONNREFUSED if we got a "Connection Refused" by the peer on any address
    *    ECONNABORTED if we failed without a "Connection refused"
    * Suitable error messages for the connection failure will already have been
    * printed.
  */   */
 int  int
 ssh_connect(const char *host, struct sockaddr_storage * hostaddr,  ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
Line 198 
Line 250 
         struct addrinfo hints, *ai, *aitop;          struct addrinfo hints, *ai, *aitop;
         struct linger linger;          struct linger linger;
         struct servent *sp;          struct servent *sp;
           /*
            * Did we get only other errors than "Connection refused" (which
            * should block fallback to rsh and similar), or did we get at least
            * one "Connection refused"?
            */
           int full_failure = 1;
   
         debug("ssh_connect: getuid %u geteuid %u anon %d",          debug("ssh_connect: getuid %u geteuid %u anon %d",
               (u_int) getuid(), (u_int) geteuid(), anonymous);                (u_int) getuid(), (u_int) geteuid(), anonymous);
Line 228 
Line 286 
          * Try to connect several times.  On some machines, the first time           * Try to connect several times.  On some machines, the first time
          * will sometimes fail.  In general socket code appears to behave           * will sometimes fail.  In general socket code appears to behave
          * quite magically on many machines.           * quite magically on many machines.
          */                   */
         for (attempt = 0; attempt < connection_attempts; attempt++) {          for (attempt = 0; ;) {
                 if (attempt > 0)                  if (attempt > 0)
                         debug("Trying again...");                          debug("Trying again...");
   
Line 252 
Line 310 
                             !anonymous && geteuid() == 0,                              !anonymous && geteuid() == 0,
                             ai->ai_family);                              ai->ai_family);
                         if (sock < 0)                          if (sock < 0)
                                   /* Any error is already output */
                                 continue;                                  continue;
   
                         /* Connect to the host.  We use the user's uid in the                          /* Connect to the host.  We use the user's uid in the
Line 265 
Line 324 
                                 restore_uid();                                  restore_uid();
                                 break;                                  break;
                         } else {                          } else {
                                 debug("connect: %.100s", strerror(errno));                                  if (errno == ECONNREFUSED)
                                           full_failure = 0;
                                   log("ssh: connect to address %s port %s: %s",
                                       sockaddr_ntop(ai->ai_addr), strport,
                                       strerror(errno));
                                 restore_uid();                                  restore_uid();
                                 /*                                  /*
                                  * Close the failed socket; there appear to                                   * Close the failed socket; there appear to
Line 280 
Line 343 
                 if (ai)                  if (ai)
                         break;  /* Successful connection. */                          break;  /* Successful connection. */
   
                   attempt++;
                   if (attempt >= connection_attempts)
                           break;
                 /* Sleep a moment before retrying. */                  /* Sleep a moment before retrying. */
                 sleep(1);                  sleep(1);
         }          }
Line 288 
Line 354 
   
         /* Return failure if we didn't get a successful connection. */          /* Return failure if we didn't get a successful connection. */
         if (attempt >= connection_attempts)          if (attempt >= connection_attempts)
                 return 0;                  return full_failure ? ECONNABORTED : ECONNREFUSED;
   
         debug("Connection established.");          debug("Connection established.");
   
Line 310 
Line 376 
         /* Set the connection. */          /* Set the connection. */
         packet_set_connection(sock, sock);          packet_set_connection(sock, sock);
   
         return 1;          return 0;
 }  }
   
 /*  /*
  * Waits for the server identification string, and sends our own   * Waits for the server identification string, and sends our own
  * identification string.   * identification string.
  */   */
 void  static void
 ssh_exchange_identification(void)  ssh_exchange_identification(void)
 {  {
         char buf[256], remote_version[256];     /* must be same size! */          char buf[256], remote_version[256];     /* must be same size! */
Line 402 
Line 468 
                 fatal("Protocol major versions differ: %d vs. %d",                  fatal("Protocol major versions differ: %d vs. %d",
                     (options.protocol & SSH_PROTO_2) ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1,                      (options.protocol & SSH_PROTO_2) ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1,
                     remote_major);                      remote_major);
         if (compat20)  
                 packet_set_ssh2_format();  
         /* Send our own protocol version identification. */          /* Send our own protocol version identification. */
         snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n",          snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n",
             compat20 ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1,              compat20 ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1,
Line 418 
Line 482 
 }  }
   
 /* defaults to 'no' */  /* defaults to 'no' */
 int  static int
 read_yes_or_no(const char *prompt, int defval)  read_yes_or_no(const char *prompt, int defval)
 {  {
         char buf[1024];          char buf[1024];
Line 441 
Line 505 
         while (1) {          while (1) {
                 fprintf(stderr, "%s", prompt);                  fprintf(stderr, "%s", prompt);
                 if (fgets(buf, sizeof(buf), f) == NULL) {                  if (fgets(buf, sizeof(buf), f) == NULL) {
                         /* Print a newline (the prompt probably didn\'t have one). */                          /*
                            * Print a newline (the prompt probably didn\'t have
                            * one).
                            */
                         fprintf(stderr, "\n");                          fprintf(stderr, "\n");
                         strlcpy(buf, "no", sizeof buf);                          strlcpy(buf, "no", sizeof buf);
                 }                  }
Line 467 
Line 534 
 }  }
   
 /*  /*
  * check whether the supplied host key is valid, return only if ok.   * check whether the supplied host key is valid, return -1 if the key
    * is not valid. the user_hostfile will not be updated if 'readonly' is true.
  */   */
   
 void  static int
 check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,  check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
         const char *user_hostfile, const char *system_hostfile)      int readonly, const char *user_hostfile, const char *system_hostfile)
 {  {
         Key *file_key;          Key *file_key;
         char *type = key_type(host_key);          char *type = key_type(host_key);
Line 496 
Line 564 
         /**  hostaddr == 0! */          /**  hostaddr == 0! */
         switch (hostaddr->sa_family) {          switch (hostaddr->sa_family) {
         case AF_INET:          case AF_INET:
                 local = (ntohl(((struct sockaddr_in *)hostaddr)->sin_addr.s_addr) >> 24) == IN_LOOPBACKNET;                  local = (ntohl(((struct sockaddr_in *)hostaddr)->
                      sin_addr.s_addr) >> 24) == IN_LOOPBACKNET;
                 break;                  break;
         case AF_INET6:          case AF_INET6:
                 local = IN6_IS_ADDR_LOOPBACK(&(((struct sockaddr_in6 *)hostaddr)->sin6_addr));                  local = IN6_IS_ADDR_LOOPBACK(
                       &(((struct sockaddr_in6 *)hostaddr)->sin6_addr));
                 break;                  break;
         default:          default:
                 local = 0;                  local = 0;
Line 508 
Line 578 
         if (local && options.host_key_alias == NULL) {          if (local && options.host_key_alias == NULL) {
                 debug("Forcing accepting of host key for "                  debug("Forcing accepting of host key for "
                     "loopback/localhost.");                      "loopback/localhost.");
                 return;                  return 0;
         }          }
   
         /*          /*
Line 552 
Line 622 
          * hosts or in the systemwide list.           * hosts or in the systemwide list.
          */           */
         host_file = user_hostfile;          host_file = user_hostfile;
         host_status = check_host_in_hostfile(host_file, host, host_key, file_key, &host_line);          host_status = check_host_in_hostfile(host_file, host, host_key,
                file_key, &host_line);
         if (host_status == HOST_NEW) {          if (host_status == HOST_NEW) {
                 host_file = system_hostfile;                  host_file = system_hostfile;
                 host_status = check_host_in_hostfile(host_file, host, host_key, file_key, &host_line);                  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           * Also perform check for the ip address, skip the check if we are
Line 565 
Line 637 
                 Key *ip_key = key_new(host_key->type);                  Key *ip_key = key_new(host_key->type);
   
                 ip_file = user_hostfile;                  ip_file = user_hostfile;
                 ip_status = check_host_in_hostfile(ip_file, ip, host_key, ip_key, &ip_line);                  ip_status = check_host_in_hostfile(ip_file, ip, host_key,
                       ip_key, &ip_line);
                 if (ip_status == HOST_NEW) {                  if (ip_status == HOST_NEW) {
                         ip_file = system_hostfile;                          ip_file = system_hostfile;
                         ip_status = check_host_in_hostfile(ip_file, ip, host_key, ip_key, &ip_line);                          ip_status = check_host_in_hostfile(ip_file, ip,
                               host_key, ip_key, &ip_line);
                 }                  }
                 if (host_status == HOST_CHANGED &&                  if (host_status == HOST_CHANGED &&
                     (ip_status != HOST_CHANGED || !key_equal(ip_key, file_key)))                      (ip_status != HOST_CHANGED || !key_equal(ip_key, file_key)))
Line 587 
Line 661 
                     host, type);                      host, type);
                 debug("Found key in %s:%d", host_file, host_line);                  debug("Found key in %s:%d", host_file, host_line);
                 if (options.check_host_ip && ip_status == HOST_NEW) {                  if (options.check_host_ip && ip_status == HOST_NEW) {
                         if (!add_host_to_hostfile(user_hostfile, ip, host_key))                          if (readonly)
                                 log("Failed to add the %s host key for IP address '%.128s' to the list of known hosts (%.30s).",                                  log("%s host key for IP address "
                                     type, ip, user_hostfile);                                      "'%.128s' not in list of known hosts.",
                         else  
                                 log("Warning: Permanently added the %s host key for IP address '%.128s' to the list of known hosts.",  
                                     type, ip);                                      type, ip);
                           else if (!add_host_to_hostfile(user_hostfile, ip,
                                host_key))
                                   log("Failed to add the %s host key for IP "
                                       "address '%.128s' to the list of known "
                                       "hosts (%.30s).", type, ip, user_hostfile);
                           else
                                   log("Warning: Permanently added the %s host "
                                       "key for IP address '%.128s' to the list "
                                       "of known hosts.", type, ip);
                 }                  }
                 break;                  break;
         case HOST_NEW:          case HOST_NEW:
                   if (readonly)
                           goto fail;
                 /* The host is new. */                  /* The host is new. */
                 if (options.strict_host_key_checking == 1) {                  if (options.strict_host_key_checking == 1) {
                         /* User has requested strict host key checking.  We will not add the host key                          /*
                            automatically.  The only alternative left is to abort. */                           * User has requested strict host key checking.  We
                         fatal("No %s host key is known for %.200s and you have requested strict checking.", type, host);                           * will not add the host key automatically.  The only
                            * alternative left is to abort.
                            */
                           error("No %s host key is known for %.200s and you "
                               "have requested strict checking.", type, host);
                           goto fail;
                 } else if (options.strict_host_key_checking == 2) {                  } else if (options.strict_host_key_checking == 2) {
                         /* The default */                          /* The default */
                         char prompt[1024];                          char prompt[1024];
                         fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);                          fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
                         snprintf(prompt, sizeof(prompt),                          snprintf(prompt, sizeof(prompt),
                             "The authenticity of host '%.200s (%s)' can't be established.\n"                              "The authenticity of host '%.200s (%s)' can't be "
                               "established.\n"
                             "%s key fingerprint is %s.\n"                              "%s key fingerprint is %s.\n"
                             "Are you sure you want to continue connecting (yes/no)? ",                              "Are you sure you want to continue connecting "
                             host, ip, type, fp);                              "(yes/no)? ", host, ip, type, fp);
                         xfree(fp);                          xfree(fp);
                         if (!read_yes_or_no(prompt, -1))                          if (!read_yes_or_no(prompt, -1)) {
                                 fatal("Aborted by user!");                                  log("Aborted by user!");
                                   goto fail;
                           }
                 }                  }
                 if (options.check_host_ip && ip_status == HOST_NEW) {                  if (options.check_host_ip && ip_status == HOST_NEW) {
                         snprintf(hostline, sizeof(hostline), "%s,%s", host, ip);                          snprintf(hostline, sizeof(hostline), "%s,%s", host, ip);
Line 620 
Line 711 
                 } else                  } else
                         hostp = host;                          hostp = host;
   
                 /* If not in strict mode, add the key automatically to the local known_hosts file. */                  /*
                    * If not in strict mode, add the key automatically to the
                    * local known_hosts file.
                    */
                 if (!add_host_to_hostfile(user_hostfile, hostp, host_key))                  if (!add_host_to_hostfile(user_hostfile, hostp, host_key))
                         log("Failed to add the host to the list of known hosts (%.500s).",                          log("Failed to add the host to the list of known "
                             user_hostfile);                              "hosts (%.500s).", user_hostfile);
                 else                  else
                         log("Warning: Permanently added '%.200s' (%s) to the list of known hosts.",                          log("Warning: Permanently added '%.200s' (%s) to the "
                             hostp, type);                              "list of known hosts.", hostp, type);
                 break;                  break;
         case HOST_CHANGED:          case HOST_CHANGED:
                 if (options.check_host_ip && host_ip_differ) {                  if (options.check_host_ip && host_ip_differ) {
Line 668 
Line 762 
                  * If strict host key checking is in use, the user will have                   * If strict host key checking is in use, the user will have
                  * to edit the key manually and we can only abort.                   * to edit the key manually and we can only abort.
                  */                   */
                 if (options.strict_host_key_checking)                  if (options.strict_host_key_checking) {
                         fatal("%s host key for %.200s has changed and you have requested strict checking.", type, host);                          error("%s host key for %.200s has changed and you have "
                               "requested strict checking.", type, host);
                           goto fail;
                   }
   
                 /*                  /*
                  * If strict host key checking has not been requested, allow                   * If strict host key checking has not been requested, allow
Line 677 
Line 774 
                  * agent forwarding.                   * agent forwarding.
                  */                   */
                 if (options.password_authentication) {                  if (options.password_authentication) {
                         error("Password authentication is disabled to avoid trojan horses.");                          error("Password authentication is disabled to avoid "
                               "man-in-the-middle attacks.");
                         options.password_authentication = 0;                          options.password_authentication = 0;
                 }                  }
                 if (options.forward_agent) {                  if (options.forward_agent) {
                         error("Agent forwarding is disabled to avoid trojan horses.");                          error("Agent forwarding is disabled to avoid "
                               "man-in-the-middle attacks.");
                         options.forward_agent = 0;                          options.forward_agent = 0;
                 }                  }
                 if (options.forward_x11) {                  if (options.forward_x11) {
                         error("X11 forwarding is disabled to avoid trojan horses.");                          error("X11 forwarding is disabled to avoid "
                               "man-in-the-middle attacks.");
                         options.forward_x11 = 0;                          options.forward_x11 = 0;
                 }                  }
                 if (options.num_local_forwards > 0 || options.num_remote_forwards > 0) {                  if (options.num_local_forwards > 0 ||
                         error("Port forwarding is disabled to avoid trojan horses.");                      options.num_remote_forwards > 0) {
                         options.num_local_forwards = options.num_remote_forwards = 0;                          error("Port forwarding is disabled to avoid "
                               "man-in-the-middle attacks.");
                           options.num_local_forwards =
                                options.num_remote_forwards = 0;
                 }                  }
                 /*                  /*
                  * XXX Should permit the user to change to use the new id.                   * XXX Should permit the user to change to use the new id.
Line 711 
Line 814 
                         log("Matching host key in %s:%d", host_file, host_line);                          log("Matching host key in %s:%d", host_file, host_line);
                 log("Offending key for IP in %s:%d", ip_file, ip_line);                  log("Offending key for IP in %s:%d", ip_file, ip_line);
                 if (options.strict_host_key_checking == 1) {                  if (options.strict_host_key_checking == 1) {
                         fatal("Exiting, you have requested strict checking.");                          error("Exiting, you have requested strict checking.");
                           goto fail;
                 } else if (options.strict_host_key_checking == 2) {                  } else if (options.strict_host_key_checking == 2) {
                         if (!read_yes_or_no("Are you sure you want " \                          if (!read_yes_or_no("Are you sure you want "
                             "to continue connecting (yes/no)? ", -1))                              "to continue connecting (yes/no)? ", -1)) {
                                 fatal("Aborted by user!");                                  log("Aborted by user!");
                                   goto fail;
                           }
                 }                  }
         }          }
   
         xfree(ip);          xfree(ip);
           return 0;
   
   fail:
           xfree(ip);
           return -1;
 }  }
   
   int
   verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
   {
           struct stat st;
   
           /* return ok if the key can be found in an old keyfile */
           if (stat(options.system_hostfile2, &st) == 0 ||
               stat(options.user_hostfile2, &st) == 0) {
                   if (check_host_key(host, hostaddr, host_key, /*readonly*/ 1,
                       options.user_hostfile2, options.system_hostfile2) == 0)
                           return 0;
           }
           return check_host_key(host, hostaddr, host_key, /*readonly*/ 0,
               options.user_hostfile, options.system_hostfile);
   }
   
 /*  /*
  * Starts a dialog with the server, and authenticates the current user on the   * Starts a dialog with the server, and authenticates the current user on the
  * server.  This does not need any extra privileges.  The basic connection   * server.  This does not need any extra privileges.  The basic connection
Line 769 
Line 896 
         char *padded;          char *padded;
   
         if (datafellows & SSH_BUG_PASSWORDPAD) {          if (datafellows & SSH_BUG_PASSWORDPAD) {
                 packet_put_string(password, strlen(password));                  packet_put_cstring(password);
                 return;                  return;
         }          }
         size = roundup(strlen(password) + 1, 32);          size = roundup(strlen(password) + 1, 32);

Legend:
Removed from v.1.104  
changed lines
  Added in v.1.104.2.1