[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.341 and 1.342

version 1.341, 2020/10/18 11:32:02 version 1.342, 2020/11/12 22:56:00
Line 662 
Line 662 
         return 0;          return 0;
 }  }
   
   struct find_by_key_ctx {
           const char *host, *ip;
           const struct sshkey *key;
           char **names;
           u_int nnames;
   };
   
   /* Try to replace home directory prefix (per $HOME) with a ~/ sequence */
   static char *
   try_tilde_unexpand(const char *path)
   {
           char *home, *ret = NULL;
           size_t l;
   
           if (*path != '/')
                   return xstrdup(path);
           if ((home = getenv("HOME")) == NULL || (l = strlen(home)) == 0)
                   return xstrdup(path);
           if (strncmp(path, home, l) != 0)
                   return xstrdup(path);
           /*
            * ensure we have matched on a path boundary: either the $HOME that
            * we just compared ends with a '/' or the next character of the path
            * must be a '/'.
            */
           if (home[l - 1] != '/' && path[l] != '/')
                   return xstrdup(path);
           if (path[l] == '/')
                   l++;
           xasprintf(&ret, "~/%s", path + l);
           return ret;
   }
   
   static int
   hostkeys_find_by_key_cb(struct hostkey_foreach_line *l, void *_ctx)
   {
           struct find_by_key_ctx *ctx = (struct find_by_key_ctx *)_ctx;
           char *path;
   
           /* we are looking for keys with names that *do not* match */
           if ((l->match & HKF_MATCH_HOST) != 0)
                   return 0;
           /* not interested in marker lines */
           if (l->marker != MRK_NONE)
                   return 0;
           /* we are only interested in exact key matches */
           if (l->key == NULL || !sshkey_equal(ctx->key, l->key))
                   return 0;
           path = try_tilde_unexpand(l->path);
           debug_f("found matching key in %s:%lu", path, l->linenum);
           ctx->names = xrecallocarray(ctx->names,
               ctx->nnames, ctx->nnames + 1, sizeof(*ctx->names));
           xasprintf(&ctx->names[ctx->nnames], "%s:%lu: %s", path, l->linenum,
               strncmp(l->hosts, HASH_MAGIC, strlen(HASH_MAGIC)) == 0 ?
               "[hashed name]" : l->hosts);
           ctx->nnames++;
           free(path);
           return 0;
   }
   
   static int
   hostkeys_find_by_key_hostfile(const char *file, const char *which,
       struct find_by_key_ctx *ctx)
   {
           int r;
   
           debug3_f("trying %s hostfile \"%s\"", which, file);
           if ((r = hostkeys_foreach(file, hostkeys_find_by_key_cb, ctx,
               ctx->host, ctx->ip, HKF_WANT_PARSE_KEY)) != 0) {
                   if (r == SSH_ERR_SYSTEM_ERROR && errno == ENOENT) {
                           debug_f("hostkeys file %s does not exist", file);
                           return 0;
                   }
                   error_fr(r, "hostkeys_foreach failed for %s", file);
                   return r;
           }
           return 0;
   }
   
 /*  /*
    * Find 'key' in known hosts file(s) that do not match host/ip.
    * Used to display also-known-as information for previously-unseen hostkeys.
    */
   static void
   hostkeys_find_by_key(const char *host, const char *ip, const struct sshkey *key,
       char **user_hostfiles, u_int num_user_hostfiles,
       char **system_hostfiles, u_int num_system_hostfiles,
       char ***names, u_int *nnames)
   {
           struct find_by_key_ctx ctx = {0};
           u_int i;
   
           *names = NULL;
           *nnames = 0;
   
           if (key == NULL || sshkey_is_cert(key))
                   return;
   
           ctx.host = host;
           ctx.ip = ip;
           ctx.key = key;
   
           for (i = 0; i < num_user_hostfiles; i++) {
                   if (hostkeys_find_by_key_hostfile(user_hostfiles[i],
                       "user", &ctx) != 0)
                           goto fail;
           }
           for (i = 0; i < num_system_hostfiles; i++) {
                   if (hostkeys_find_by_key_hostfile(system_hostfiles[i],
                       "system", &ctx) != 0)
                           goto fail;
           }
           /* success */
           *names = ctx.names;
           *nnames = ctx.nnames;
           ctx.names = NULL;
           ctx.nnames = 0;
           return;
    fail:
           for (i = 0; i < ctx.nnames; i++)
                   free(ctx.names[i]);
           free(ctx.names);
   }
   
   #define MAX_OTHER_NAMES 8 /* Maximum number of names to list */
   static char *
   other_hostkeys_message(const char *host, const char *ip,
       const struct sshkey *key,
       char **user_hostfiles, u_int num_user_hostfiles,
       char **system_hostfiles, u_int num_system_hostfiles)
   {
           char *ret = NULL, **othernames = NULL;
           u_int i, n, num_othernames = 0;
   
           hostkeys_find_by_key(host, ip, key,
               user_hostfiles, num_user_hostfiles,
               system_hostfiles, num_system_hostfiles,
               &othernames, &num_othernames);
           if (num_othernames == 0)
                   return xstrdup("This key is not known by any other names");
   
           xasprintf(&ret, "This host key is known by the following other "
               "names/addresses:");
   
           n = num_othernames;
           if (n > MAX_OTHER_NAMES)
                   n = MAX_OTHER_NAMES;
           for (i = 0; i < n; i++) {
                   xextendf(&ret, "\n", "    %s", othernames[i]);
           }
           if (n < num_othernames) {
                   xextendf(&ret, "\n", "    (%d additional names ommitted)",
                       num_othernames - n);
           }
           for (i = 0; i < num_othernames; i++)
                   free(othernames[i]);
           free(othernames);
           return ret;
   }
   
   /*
  * 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. user_hostfile[0] will not be updated if 'readonly' is true.   * is not valid. user_hostfile[0] will not be updated if 'readonly' is true.
  */   */
Line 838 
Line 998 
                         goto fail;                          goto fail;
                 } else if (options.strict_host_key_checking ==                  } else if (options.strict_host_key_checking ==
                     SSH_STRICT_HOSTKEY_ASK) {                      SSH_STRICT_HOSTKEY_ASK) {
                         char msg1[1024], msg2[1024];                          char *msg1 = NULL, *msg2 = NULL;
   
                         if (show_other_keys(host_hostkeys, host_key))                          xasprintf(&msg1, "The authenticity of host "
                                 snprintf(msg1, sizeof(msg1),                              "'%.200s (%s)' can't be established", host, ip);
                                     "\nbut keys of different type are already"  
                                     " known for this host.");                          if (show_other_keys(host_hostkeys, host_key)) {
                         else                                  xextendf(&msg1, "\n", "but keys of different "
                                 snprintf(msg1, sizeof(msg1), ".");                                      "type are already known for this host.");
                         /* The default */                          } else
                                   xextendf(&msg1, "", ".");
   
                         fp = sshkey_fingerprint(host_key,                          fp = sshkey_fingerprint(host_key,
                             options.fingerprint_hash, SSH_FP_DEFAULT);                              options.fingerprint_hash, SSH_FP_DEFAULT);
                         ra = sshkey_fingerprint(host_key,                          ra = sshkey_fingerprint(host_key,
                             options.fingerprint_hash, SSH_FP_RANDOMART);                              options.fingerprint_hash, SSH_FP_RANDOMART);
                         if (fp == NULL || ra == NULL)                          if (fp == NULL || ra == NULL)
                                 fatal_f("sshkey_fingerprint failed");                                  fatal_f("sshkey_fingerprint failed");
                         msg2[0] = '\0';                          xextendf(&msg1, "\n", "%s key fingerprint is %s.",
                               type, fp);
                           if (options.visual_host_key)
                                   xextendf(&msg1, "\n", "%s", ra);
                         if (options.verify_host_key_dns) {                          if (options.verify_host_key_dns) {
                                 if (matching_host_key_dns)                                  xextendf(&msg1, "\n",
                                         snprintf(msg2, sizeof(msg2),                                      "%s host key fingerprint found in DNS.",
                                             "Matching host key fingerprint"                                      matching_host_key_dns ?
                                             " found in DNS.\n");                                      "Matching" : "No matching");
                                 else  
                                         snprintf(msg2, sizeof(msg2),  
                                             "No matching host key fingerprint"  
                                             " found in DNS.\n");  
                         }                          }
                         snprintf(msg, sizeof(msg),                          /* msg2 informs for other names matching this key */
                             "The authenticity of host '%.200s (%s)' can't be "                          if ((msg2 = other_hostkeys_message(host, ip, host_key,
                             "established%s\n"                              user_hostfiles, num_user_hostfiles,
                             "%s key fingerprint is %s.%s%s\n%s"                              system_hostfiles, num_system_hostfiles)) != NULL)
                                   xextendf(&msg1, "\n", "%s", msg2);
   
                           xextendf(&msg1, "\n",
                             "Are you sure you want to continue connecting "                              "Are you sure you want to continue connecting "
                             "(yes/no/[fingerprint])? ",                              "(yes/no/[fingerprint])? ");
                             host, ip, msg1, type, fp,  
                             options.visual_host_key ? "\n" : "",                          confirmed = confirm(msg1, fp);
                             options.visual_host_key ? ra : "",  
                             msg2);  
                         free(ra);                          free(ra);
                         confirmed = confirm(msg, fp);  
                         free(fp);                          free(fp);
                           free(msg1);
                           free(msg2);
                         if (!confirmed)                          if (!confirmed)
                                 goto fail;                                  goto fail;
                         hostkey_trusted = 1; /* user explicitly confirmed */                          hostkey_trusted = 1; /* user explicitly confirmed */

Legend:
Removed from v.1.341  
changed lines
  Added in v.1.342