[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.115.2.4 and 1.116

version 1.115.2.4, 2002/10/11 14:53:07 version 1.116, 2001/12/05 10:06:13
Line 31 
Line 31 
 #include "readconf.h"  #include "readconf.h"
 #include "atomicio.h"  #include "atomicio.h"
 #include "misc.h"  #include "misc.h"
 #include "readpass.h"  
   
 char *client_version_string = NULL;  char *client_version_string = NULL;
 char *server_version_string = NULL;  char *server_version_string = NULL;
   
 /* import */  
 extern Options options;  extern Options options;
 extern char *__progname;  extern char *__progname;
 extern uid_t original_real_uid;  
 extern uid_t original_effective_uid;  
 extern pid_t proxy_command_pid;  
   
 static int show_other_keys(const char *, Key *);  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();        /* XXX abort is bad -- do something else */
           }
           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.
  */   */
 static int  static int
 ssh_proxy_connect(const char *host, u_short port, const char *proxy_command)  ssh_proxy_connect(const char *host, u_short port, struct passwd *pw,
                     const char *proxy_command)
 {  {
         Buffer command;          Buffer command;
         const char *cp;          const char *cp;
Line 61 
Line 76 
         /* Convert the port number into a string. */          /* Convert the port number into a string. */
         snprintf(strport, sizeof strport, "%hu", port);          snprintf(strport, sizeof strport, "%hu", port);
   
         /*          /* Build the final command string in the buffer by making the
          * Build the final command string in the buffer by making the             appropriate substitutions to the given proxy command. */
          * appropriate substitutions to the given proxy command.  
          *  
          * Use "exec" to avoid "sh -c" processes on some platforms  
          * (e.g. Solaris)  
          */  
         buffer_init(&command);          buffer_init(&command);
         buffer_append(&command, "exec ", 5);  
   
         for (cp = proxy_command; *cp; cp++) {          for (cp = proxy_command; *cp; cp++) {
                 if (cp[0] == '%' && cp[1] == '%') {                  if (cp[0] == '%' && cp[1] == '%') {
                         buffer_append(&command, "%", 1);                          buffer_append(&command, "%", 1);
Line 97 
Line 105 
         /* Create pipes for communicating with the proxy. */          /* Create pipes for communicating with the proxy. */
         if (pipe(pin) < 0 || pipe(pout) < 0)          if (pipe(pin) < 0 || pipe(pout) < 0)
                 fatal("Could not create pipes to communicate with the proxy: %.100s",                  fatal("Could not create pipes to communicate with the proxy: %.100s",
                     strerror(errno));                        strerror(errno));
   
         debug("Executing proxy command: %.500s", command_string);          debug("Executing proxy command: %.500s", command_string);
   
Line 106 
Line 114 
                 char *argv[10];                  char *argv[10];
   
                 /* Child.  Permanently give up superuser privileges. */                  /* Child.  Permanently give up superuser privileges. */
                 seteuid(original_real_uid);                  permanently_set_uid(pw);
                 setuid(original_real_uid);  
   
                 /* Redirect stdin and stdout. */                  /* Redirect stdin and stdout. */
                 close(pin[1]);                  close(pin[1]);
Line 138 
Line 145 
         /* Parent. */          /* Parent. */
         if (pid < 0)          if (pid < 0)
                 fatal("fork failed: %.100s", strerror(errno));                  fatal("fork failed: %.100s", strerror(errno));
         else  
                 proxy_command_pid = pid; /* save pid to clean up later */  
   
         /* Close child side of the descriptors. */          /* Close child side of the descriptors. */
         close(pin[0]);          close(pin[0]);
Line 159 
Line 164 
  * Creates a (possibly privileged) socket for use as the ssh connection.   * Creates a (possibly privileged) socket for use as the ssh connection.
  */   */
 static int  static int
 ssh_create_socket(int privileged, int family)  ssh_create_socket(struct passwd *pw, int privileged, int family)
 {  {
         int sock, gaierr;          int sock, gaierr;
         struct addrinfo hints, *res;          struct addrinfo hints, *res;
Line 170 
Line 175 
          */           */
         if (privileged) {          if (privileged) {
                 int p = IPPORT_RESERVED - 1;                  int p = IPPORT_RESERVED - 1;
                 PRIV_START;  
                 sock = rresvport_af(&p, family);                  sock = rresvport_af(&p, family);
                 PRIV_END;  
                 if (sock < 0)                  if (sock < 0)
                         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);
                 return sock;                  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);          sock = socket(family, SOCK_STREAM, 0);
         if (sock < 0)          if (sock < 0)
                 error("socket: %.100s", strerror(errno));                  error("socket: %.100s", strerror(errno));
           restore_uid();
   
         /* Bind the socket to an alternative local IP address */          /* Bind the socket to an alternative local IP address */
         if (options.bind_address == NULL)          if (options.bind_address == NULL)
Line 211 
Line 220 
 /*  /*
  * Opens a TCP/IP connection to the remote server on the given host.   * Opens a TCP/IP connection to the remote server on the given host.
  * The address of the remote host will be returned in hostaddr.   * The address of the remote host will be returned in hostaddr.
  * If port is 0, the default port will be used.  If needpriv is true,   * If port is 0, the default port will be used.  If anonymous is zero,
  * a privileged port will be allocated to make the connection.   * a privileged port will be allocated to make the connection.
  * This requires super-user privileges if needpriv is true.   * This requires super-user privileges if anonymous is false.
  * Connection_attempts specifies the maximum number of tries (one per   * Connection_attempts specifies the maximum number of tries (one per
  * 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
Line 228 
Line 237 
 int  int
 ssh_connect(const char *host, struct sockaddr_storage * hostaddr,  ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
     u_short port, int family, int connection_attempts,      u_short port, int family, int connection_attempts,
     int needpriv, const char *proxy_command)      int anonymous, struct passwd *pw, const char *proxy_command)
 {  {
         int gaierr;          int gaierr;
         int on = 1;          int on = 1;
         int sock = -1, attempt;          int sock = -1, attempt;
         char ntop[NI_MAXHOST], strport[NI_MAXSERV];          char ntop[NI_MAXHOST], strport[NI_MAXSERV];
         struct addrinfo hints, *ai, *aitop;          struct addrinfo hints, *ai, *aitop;
           struct linger linger;
         struct servent *sp;          struct servent *sp;
         /*          /*
          * Did we get only other errors than "Connection refused" (which           * Did we get only other errors than "Connection refused" (which
Line 243 
Line 253 
          */           */
         int full_failure = 1;          int full_failure = 1;
   
         debug("ssh_connect: needpriv %d", needpriv);          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. */          /* Get default port if port has not been set. */
         if (port == 0) {          if (port == 0) {
Line 255 
Line 266 
         }          }
         /* If a proxy command is given, connect using it. */          /* If a proxy command is given, connect using it. */
         if (proxy_command != NULL)          if (proxy_command != NULL)
                 return ssh_proxy_connect(host, port, proxy_command);                  return ssh_proxy_connect(host, port, pw, proxy_command);
   
         /* No proxy command. */          /* No proxy command. */
   
         memset(&hints, 0, sizeof(hints));          memset(&hints, 0, sizeof(hints));
         hints.ai_family = family;          hints.ai_family = family;
         hints.ai_socktype = SOCK_STREAM;          hints.ai_socktype = SOCK_STREAM;
         snprintf(strport, sizeof strport, "%u", port);          snprintf(strport, sizeof strport, "%d", port);
         if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0)          if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0)
                 fatal("%s: %.100s: %s", __progname, host,                  fatal("%s: %.100s: %s", __progname, host,
                     gai_strerror(gaierr));                      gai_strerror(gaierr));
Line 291 
Line 302 
                                 host, ntop, strport);                                  host, ntop, strport);
   
                         /* Create a socket for connecting. */                          /* Create a socket for connecting. */
                         sock = ssh_create_socket(needpriv, ai->ai_family);                          sock = ssh_create_socket(pw,
                               !anonymous && geteuid() == 0,
                               ai->ai_family);
                         if (sock < 0)                          if (sock < 0)
                                 /* Any error is already output */                                  /* Any error is already output */
                                 continue;                                  continue;
   
                           /* Connect to the host.  We use the user's uid in the
                            * hope that it will help with tcp_wrappers showing
                            * the remote uid as root.
                            */
                           temporarily_use_uid(pw);
                         if (connect(sock, ai->ai_addr, ai->ai_addrlen) >= 0) {                          if (connect(sock, ai->ai_addr, ai->ai_addrlen) >= 0) {
                                 /* Successful connection. */                                  /* Successful connection. */
                                 memcpy(hostaddr, ai->ai_addr, ai->ai_addrlen);                                  memcpy(hostaddr, ai->ai_addr, ai->ai_addrlen);
                                   restore_uid();
                                 break;                                  break;
                         } else {                          } else {
                                 if (errno == ECONNREFUSED)                                  if (errno == ECONNREFUSED)
                                         full_failure = 0;                                          full_failure = 0;
                                 debug("connect to address %s port %s: %s",                                  log("ssh: connect to address %s port %s: %s",
                                     ntop, strport, strerror(errno));                                      sockaddr_ntop(ai->ai_addr), strport,
                                       strerror(errno));
                                   restore_uid();
                                 /*                                  /*
                                  * Close the failed socket; there appear to                                   * Close the failed socket; there appear to
                                  * be some problems when reusing a socket for                                   * be some problems when reusing a socket for
                                  * which connect() has already returned an                                   * which connect() has already returned an
                                  * error.                                   * error.
                                  */                                   */
                                   shutdown(sock, SHUT_RDWR);
                                 close(sock);                                  close(sock);
                         }                          }
                 }                  }
Line 327 
Line 349 
         freeaddrinfo(aitop);          freeaddrinfo(aitop);
   
         /* 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)
                 log("ssh: connect to host %s port %s: %s",  
                     host, strport, strerror(errno));  
                 return full_failure ? ECONNABORTED : ECONNREFUSED;                  return full_failure ? ECONNABORTED : ECONNREFUSED;
         }  
   
         debug("Connection established.");          debug("Connection established.");
   
           /*
            * Set socket options.  We would like the socket to disappear as soon
            * as it has been closed for whatever reason.
            */
           /* setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)); */
           linger.l_onoff = 1;
           linger.l_linger = 5;
           setsockopt(sock, SOL_SOCKET, SO_LINGER, (void *)&linger, sizeof(linger));
   
         /* Set keepalives if requested. */          /* Set keepalives if requested. */
         if (options.keepalives &&          if (options.keepalives &&
             setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&on,              setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&on,
Line 393 
Line 421 
             &remote_major, &remote_minor, remote_version) != 3)              &remote_major, &remote_minor, remote_version) != 3)
                 fatal("Bad remote protocol version identification: '%.100s'", buf);                  fatal("Bad remote protocol version identification: '%.100s'", buf);
         debug("Remote protocol version %d.%d, remote software version %.100s",          debug("Remote protocol version %d.%d, remote software version %.100s",
             remote_major, remote_minor, remote_version);                remote_major, remote_minor, remote_version);
   
         compat_datafellows(remote_version);          compat_datafellows(remote_version);
         mismatch = 0;          mismatch = 0;
Line 453 
Line 481 
 static int  static int
 confirm(const char *prompt)  confirm(const char *prompt)
 {  {
         const char *msg, *again = "Please type 'yes' or 'no': ";          char buf[1024];
         char *p;          FILE *f;
         int ret = -1;          int retval = -1;
   
         if (options.batch_mode)          if (options.batch_mode)
                 return 0;                  return 0;
         for (msg = prompt;;msg = again) {          if (isatty(STDIN_FILENO))
                 p = read_passphrase(msg, RP_ECHO);                  f = stdin;
                 if (p == NULL ||          else
                     (p[0] == '\0') || (p[0] == '\n') ||                  f = fopen(_PATH_TTY, "rw");
                     strncasecmp(p, "no", 2) == 0)          if (f == NULL)
                         ret = 0;                  return 0;
                 if (p && strncasecmp(p, "yes", 3) == 0)          fflush(stdout);
                         ret = 1;          fprintf(stderr, "%s", prompt);
                 if (p)          while (1) {
                         xfree(p);                  if (fgets(buf, sizeof(buf), f) == NULL) {
                 if (ret != -1)                          fprintf(stderr, "\n");
                         return ret;                          strlcpy(buf, "no", sizeof buf);
                   }
                   /* Remove newline from response. */
                   if (strchr(buf, '\n'))
                           *strchr(buf, '\n') = 0;
                   if (strcmp(buf, "yes") == 0)
                           retval = 1;
                   else if (strcmp(buf, "no") == 0)
                           retval = 0;
                   else
                           fprintf(stderr, "Please type 'yes' or 'no': ");
   
                   if (retval != -1) {
                           if (f != stdin)
                                   fclose(f);
                           return retval;
                   }
         }          }
 }  }
   
Line 478 
Line 522 
  * check whether the supplied host key is valid, return -1 if the key   * 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.   * is not valid. the user_hostfile will not be updated if 'readonly' is true.
  */   */
   
 static int  static int
 check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,  check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
     int readonly, const char *user_hostfile, const char *system_hostfile)      int readonly, const char *user_hostfile, const char *system_hostfile)
Line 490 
Line 535 
         HostStatus ip_status;          HostStatus ip_status;
         int local = 0, host_ip_differ = 0;          int local = 0, host_ip_differ = 0;
         char ntop[NI_MAXHOST];          char ntop[NI_MAXHOST];
         char msg[1024];          int host_line, ip_line;
         int len, host_line, ip_line, has_keys;  
         const char *host_file = NULL, *ip_file = NULL;          const char *host_file = NULL, *ip_file = NULL;
   
         /*          /*
Line 565 
Line 609 
          */           */
         host_file = user_hostfile;          host_file = user_hostfile;
         host_status = check_host_in_hostfile(host_file, host, host_key,          host_status = check_host_in_hostfile(host_file, host, host_key,
             file_key, &host_line);               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,                  host_status = check_host_in_hostfile(host_file, host, host_key,
Line 608 
Line 652 
                                     "'%.128s' not in list of known hosts.",                                      "'%.128s' not in list of known hosts.",
                                     type, ip);                                      type, ip);
                         else if (!add_host_to_hostfile(user_hostfile, ip,                          else if (!add_host_to_hostfile(user_hostfile, ip,
                             host_key))                               host_key))
                                 log("Failed to add the %s host key for IP "                                  log("Failed to add the %s host key for IP "
                                     "address '%.128s' to the list of known "                                      "address '%.128s' to the list of known "
                                     "hosts (%.30s).", type, ip, user_hostfile);                                      "hosts (%.30s).", type, ip, user_hostfile);
Line 632 
Line 676 
                             "have requested strict checking.", type, host);                              "have requested strict checking.", type, host);
                         goto fail;                          goto fail;
                 } else if (options.strict_host_key_checking == 2) {                  } else if (options.strict_host_key_checking == 2) {
                         has_keys = show_other_keys(host, host_key);  
                         /* The default */                          /* The default */
                           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(msg, sizeof(msg),                          snprintf(prompt, sizeof(prompt),
                             "The authenticity of host '%.200s (%s)' can't be "                              "The authenticity of host '%.200s (%s)' can't be "
                             "established%s\n"                              "established.\n"
                             "%s key fingerprint is %s.\n"                              "%s key fingerprint is %s.\n"
                             "Are you sure you want to continue connecting "                              "Are you sure you want to continue connecting "
                             "(yes/no)? ",                              "(yes/no)? ", host, ip, type, fp);
                              host, ip,  
                              has_keys ? ",\nbut keys of different type are already "  
                              "known for this host." : ".",  
                              type, fp);  
                         xfree(fp);                          xfree(fp);
                         if (!confirm(msg))                          if (!confirm(prompt)) {
                                 goto fail;                                  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 737 
Line 778 
                         error("Port forwarding is disabled to avoid "                          error("Port forwarding is disabled to avoid "
                             "man-in-the-middle attacks.");                              "man-in-the-middle attacks.");
                         options.num_local_forwards =                          options.num_local_forwards =
                             options.num_remote_forwards = 0;                               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 747 
Line 788 
                  * accept the authentication.                   * accept the authentication.
                  */                   */
                 break;                  break;
         case HOST_FOUND:  
                 fatal("internal error");  
                 break;  
         }          }
   
         if (options.check_host_ip && host_status != HOST_CHANGED &&          if (options.check_host_ip && host_status != HOST_CHANGED &&
             ip_status == HOST_CHANGED) {              ip_status == HOST_CHANGED) {
                 snprintf(msg, sizeof(msg),                  log("Warning: the %s host key for '%.200s' "
                     "Warning: the %s host key for '%.200s' "                      "differs from the key for the IP address '%.128s'",
                     "differs from the key for the IP address '%.128s'"                      type, host, ip);
                     "\nOffending key for IP in %s:%d",                  if (host_status == HOST_OK)
                     type, host, ip, ip_file, ip_line);                          log("Matching host key in %s:%d", host_file, host_line);
                 if (host_status == HOST_OK) {                  log("Offending key for IP in %s:%d", ip_file, ip_line);
                         len = strlen(msg);  
                         snprintf(msg + len, sizeof(msg) - len,  
                             "\nMatching host key in %s:%d",  
                             host_file, host_line);  
                 }  
                 if (options.strict_host_key_checking == 1) {                  if (options.strict_host_key_checking == 1) {
                         log(msg);  
                         error("Exiting, you have requested strict checking.");                          error("Exiting, you have requested strict checking.");
                         goto fail;                          goto fail;
                 } else if (options.strict_host_key_checking == 2) {                  } else if (options.strict_host_key_checking == 2) {
                         strlcat(msg, "\nAre you sure you want "                          if (!confirm("Are you sure you want "
                             "to continue connecting (yes/no)? ", sizeof(msg));                              "to continue connecting (yes/no)? ")) {
                         if (!confirm(msg))  
                                 goto fail;                                  goto fail;
                 } else {                          }
                         log(msg);  
                 }                  }
         }          }
   
Line 811 
Line 841 
  * This function does not require super-user privileges.   * This function does not require super-user privileges.
  */   */
 void  void
 ssh_login(Sensitive *sensitive, const char *orighost,  ssh_login(Key **keys, int nkeys, const char *orighost,
     struct sockaddr *hostaddr, struct passwd *pw)      struct sockaddr *hostaddr, struct passwd *pw)
 {  {
         char *host, *cp;          char *host, *cp;
Line 836 
Line 866 
         /* authenticate user */          /* authenticate user */
         if (compat20) {          if (compat20) {
                 ssh_kex2(host, hostaddr);                  ssh_kex2(host, hostaddr);
                 ssh_userauth2(local_user, server_user, host, sensitive);                  ssh_userauth2(local_user, server_user, host, keys, nkeys);
         } else {          } else {
                 ssh_kex(host, hostaddr);                  ssh_kex(host, hostaddr);
                 ssh_userauth1(local_user, server_user, host, sensitive);                  ssh_userauth1(local_user, server_user, host, keys, nkeys);
         }          }
 }  }
   
Line 860 
Line 890 
         packet_put_string(padded, size);          packet_put_string(padded, size);
         memset(padded, 0, size);          memset(padded, 0, size);
         xfree(padded);          xfree(padded);
 }  
   
 static int  
 show_key_from_file(const char *file, const char *host, int keytype)  
 {  
         Key *found;  
         char *fp;  
         int line, ret;  
   
         found = key_new(keytype);  
         if ((ret = lookup_key_in_hostfile_by_type(file, host,  
             keytype, found, &line))) {  
                 fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX);  
                 log("WARNING: %s key found for host %s\n"  
                     "in %s:%d\n"  
                     "%s key fingerprint %s.",  
                     key_type(found), host, file, line,  
                     key_type(found), fp);  
                 xfree(fp);  
         }  
         key_free(found);  
         return (ret);  
 }  
   
 /* print all known host keys for a given host, but skip keys of given type */  
 static int  
 show_other_keys(const char *host, Key *key)  
 {  
         int type[] = { KEY_RSA1, KEY_RSA, KEY_DSA, -1};  
         int i, found = 0;  
   
         for (i = 0; type[i] != -1; i++) {  
                 if (type[i] == key->type)  
                         continue;  
                 if (type[i] != KEY_RSA1 &&  
                     show_key_from_file(options.user_hostfile2, host, type[i])) {  
                         found = 1;  
                         continue;  
                 }  
                 if (type[i] != KEY_RSA1 &&  
                     show_key_from_file(options.system_hostfile2, host, type[i])) {  
                         found = 1;  
                         continue;  
                 }  
                 if (show_key_from_file(options.user_hostfile, host, type[i])) {  
                         found = 1;  
                         continue;  
                 }  
                 if (show_key_from_file(options.system_hostfile, host, type[i])) {  
                         found = 1;  
                         continue;  
                 }  
                 debug2("no key of type %d for host %s", type[i], host);  
         }  
         return (found);  
 }  }

Legend:
Removed from v.1.115.2.4  
changed lines
  Added in v.1.116