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

Diff for /src/usr.bin/ssh/hostfile.c between version 1.63 and 1.64

version 1.63, 2015/01/26 13:36:53 version 1.64, 2015/02/16 22:08:57
Line 181 
Line 181 
         return 1;          return 1;
 }  }
   
 static int  
 hostfile_check_key(int bits, const struct sshkey *key, const char *host,  
     const char *filename, u_long linenum)  
 {  
 #ifdef WITH_SSH1  
         if (key == NULL || key->type != KEY_RSA1 || key->rsa == NULL)  
                 return 1;  
         if (bits != BN_num_bits(key->rsa->n)) {  
                 logit("Warning: %s, line %lu: keysize mismatch for host %s: "  
                     "actual %d vs. announced %d.",  
                     filename, linenum, host, BN_num_bits(key->rsa->n), bits);  
                 logit("Warning: replace %d with %d in %s, line %lu.",  
                     bits, BN_num_bits(key->rsa->n), filename, linenum);  
         }  
 #endif  
         return 1;  
 }  
   
 static HostkeyMarker  static HostkeyMarker
 check_markers(char **cpp)  check_markers(char **cpp)
 {  {
Line 292 
Line 274 
         ctx.num_loaded = 0;          ctx.num_loaded = 0;
         ctx.hostkeys = hostkeys;          ctx.hostkeys = hostkeys;
   
         if ((r = hostkeys_foreach(path, record_hostkey, &ctx, host,          if ((r = hostkeys_foreach(path, record_hostkey, &ctx, host, NULL,
             HKF_WANT_MATCH_HOST|HKF_WANT_PARSE_KEY)) != 0) {              HKF_WANT_MATCH|HKF_WANT_PARSE_KEY)) != 0) {
                 if (r != SSH_ERR_SYSTEM_ERROR && errno != ENOENT)                  if (r != SSH_ERR_SYSTEM_ERROR && errno != ENOENT)
                         debug("%s: hostkeys_foreach failed for %s: %s",                          debug("%s: hostkeys_foreach failed for %s: %s",
                             __func__, path, ssh_err(r));                              __func__, path, ssh_err(r));
Line 430 
Line 412 
 }  }
   
 static int  static int
 write_host_entry(FILE *f, const char *host,  write_host_entry(FILE *f, const char *host, const char *ip,
     const struct sshkey *key, int store_hash)      const struct sshkey *key, int store_hash)
 {  {
         int r, success = 0;          int r, success = 0;
Line 441 
Line 423 
                         error("%s: host_hash failed", __func__);                          error("%s: host_hash failed", __func__);
                         return 0;                          return 0;
                 }                  }
         }                  fprintf(f, "%s ", hashed_host);
         fprintf(f, "%s ", store_hash ? hashed_host : host);          } else if (ip != NULL)
                   fprintf(f, "%s,%s ", host, ip);
           else
                   fprintf(f, "%s ", host);
   
         if ((r = sshkey_write(key, f)) == 0)          if ((r = sshkey_write(key, f)) == 0)
                 success = 1;                  success = 1;
Line 468 
Line 453 
         f = fopen(filename, "a");          f = fopen(filename, "a");
         if (!f)          if (!f)
                 return 0;                  return 0;
         success = write_host_entry(f, host, key, store_hash);          success = write_host_entry(f, host, NULL, key, store_hash);
         fclose(f);          fclose(f);
         return success;          return success;
 }  }
Line 477 
Line 462 
         FILE *out;          FILE *out;
         int quiet;          int quiet;
         const char *host;          const char *host;
         int *skip_keys;          int *skip_keys; /* XXX split for host/ip? might want to ensure both */
         struct sshkey * const *keys;          struct sshkey * const *keys;
         size_t nkeys;          size_t nkeys;
           int modified;
 };  };
   
 static int  static int
 host_delete(struct hostkey_foreach_line *l, void *_ctx)  host_delete(struct hostkey_foreach_line *l, void *_ctx)
 {  {
         struct host_delete_ctx *ctx = (struct host_delete_ctx *)_ctx;          struct host_delete_ctx *ctx = (struct host_delete_ctx *)_ctx;
         int loglevel = ctx->quiet ? SYSLOG_LEVEL_DEBUG1 : SYSLOG_LEVEL_INFO;          int loglevel = ctx->quiet ? SYSLOG_LEVEL_DEBUG1 : SYSLOG_LEVEL_VERBOSE;
         size_t i;          size_t i;
   
         if (l->status == HKF_STATUS_HOST_MATCHED) {          if (l->status == HKF_STATUS_MATCHED) {
                 if (l->marker != MRK_NONE) {                  if (l->marker != MRK_NONE) {
                         /* Don't remove CA and revocation lines */                          /* Don't remove CA and revocation lines */
                         fprintf(ctx->out, "%s\n", l->line);                          fprintf(ctx->out, "%s\n", l->line);
Line 522 
Line 508 
                  * Hostname matches and has no CA/revoke marker, delete it                   * Hostname matches and has no CA/revoke marker, delete it
                  * by *not* writing the line to ctx->out.                   * by *not* writing the line to ctx->out.
                  */                   */
                 do_log2(loglevel, "%s%s%s:%ld: Host %s removed",                  do_log2(loglevel, "%s%s%s:%ld: Removed %s key for host %s",
                     ctx->quiet ? __func__ : "", ctx->quiet ? ": " : "",                      ctx->quiet ? __func__ : "", ctx->quiet ? ": " : "",
                     l->path, l->linenum, ctx->host);                      l->path, l->linenum, sshkey_type(l->key), ctx->host);
                   ctx->modified = 1;
                 return 0;                  return 0;
         }          }
         /* Retain non-matching hosts and invalid lines when deleting */          /* Retain non-matching hosts and invalid lines when deleting */
Line 538 
Line 525 
 }  }
   
 int  int
 hostfile_replace_entries(const char *filename, const char *host,  hostfile_replace_entries(const char *filename, const char *host, const char *ip,
     struct sshkey **keys, size_t nkeys, int store_hash, int quiet)      struct sshkey **keys, size_t nkeys, int store_hash, int quiet, int hash_alg)
 {  {
         int r, fd, oerrno = 0;          int r, fd, oerrno = 0;
         int loglevel = quiet ? SYSLOG_LEVEL_DEBUG1 : SYSLOG_LEVEL_INFO;          int loglevel = quiet ? SYSLOG_LEVEL_DEBUG1 : SYSLOG_LEVEL_VERBOSE;
         struct host_delete_ctx ctx;          struct host_delete_ctx ctx;
         char *temp = NULL, *back = NULL;          char *fp, *temp = NULL, *back = NULL;
         mode_t omask;          mode_t omask;
         size_t i;          size_t i;
   
Line 557 
Line 544 
                 return SSH_ERR_ALLOC_FAIL;                  return SSH_ERR_ALLOC_FAIL;
         ctx.keys = keys;          ctx.keys = keys;
         ctx.nkeys = nkeys;          ctx.nkeys = nkeys;
           ctx.modified = 0;
   
         /*          /*
          * Prepare temporary file for in-place deletion.           * Prepare temporary file for in-place deletion.
Line 582 
Line 570 
         }          }
   
         /* Remove all entries for the specified host from the file */          /* Remove all entries for the specified host from the file */
         if ((r = hostkeys_foreach(filename, host_delete, &ctx, host,          if ((r = hostkeys_foreach(filename, host_delete, &ctx, host, ip,
             HKF_WANT_PARSE_KEY)) != 0) {              HKF_WANT_PARSE_KEY)) != 0) {
                 error("%s: hostkeys_foreach failed: %s", __func__, ssh_err(r));                  error("%s: hostkeys_foreach failed: %s", __func__, ssh_err(r));
                 goto fail;                  goto fail;
Line 592 
Line 580 
         for (i = 0; i < nkeys; i++) {          for (i = 0; i < nkeys; i++) {
                 if (ctx.skip_keys[i])                  if (ctx.skip_keys[i])
                         continue;                          continue;
                 do_log2(loglevel, "%s%sadd %s key to %s",                  if ((fp = sshkey_fingerprint(keys[i], hash_alg,
                     quiet ? __func__ : "", quiet ? ": " : NULL,                      SSH_FP_DEFAULT)) == NULL) {
                     sshkey_type(keys[i]), filename);                          r = SSH_ERR_ALLOC_FAIL;
                 if (!write_host_entry(ctx.out, host, keys[i], store_hash)) {                          goto fail;
                   }
                   do_log2(loglevel, "%s%sAdding new key for %s to %s: %s %s",
                       quiet ? __func__ : "", quiet ? ": " : "", host, filename,
                       sshkey_ssh_name(keys[i]), fp);
                   free(fp);
                   if (!write_host_entry(ctx.out, host, ip, keys[i], store_hash)) {
                         r = SSH_ERR_INTERNAL_ERROR;                          r = SSH_ERR_INTERNAL_ERROR;
                         goto fail;                          goto fail;
                 }                  }
                   ctx.modified = 1;
         }          }
         fclose(ctx.out);          fclose(ctx.out);
         ctx.out = NULL;          ctx.out = NULL;
   
         /* Backup the original file and replace it with the temporary */          if (ctx.modified) {
         if (unlink(back) == -1 && errno != ENOENT) {                  /* Backup the original file and replace it with the temporary */
                 oerrno = errno;                  if (unlink(back) == -1 && errno != ENOENT) {
                 error("%s: unlink %.100s: %s", __func__, back, strerror(errno));                          oerrno = errno;
                 r = SSH_ERR_SYSTEM_ERROR;                          error("%s: unlink %.100s: %s", __func__,
                 goto fail;                              back, strerror(errno));
                           r = SSH_ERR_SYSTEM_ERROR;
                           goto fail;
                   }
                   if (link(filename, back) == -1) {
                           oerrno = errno;
                           error("%s: link %.100s to %.100s: %s", __func__,
                               filename, back, strerror(errno));
                           r = SSH_ERR_SYSTEM_ERROR;
                           goto fail;
                   }
                   if (rename(temp, filename) == -1) {
                           oerrno = errno;
                           error("%s: rename \"%s\" to \"%s\": %s", __func__,
                               temp, filename, strerror(errno));
                           r = SSH_ERR_SYSTEM_ERROR;
                           goto fail;
                   }
           } else {
                   /* No changes made; just delete the temporary file */
                   if (unlink(temp) != 0)
                           error("%s: unlink \"%s\": %s", __func__,
                               temp, strerror(errno));
         }          }
         if (link(filename, back) == -1) {  
                 oerrno = errno;  
                 error("%s: link %.100s to %.100s: %s", __func__, filename, back,  
                     strerror(errno));  
                 r = SSH_ERR_SYSTEM_ERROR;  
                 goto fail;  
         }  
         if (rename(temp, filename) == -1) {  
                 oerrno = errno;  
                 error("%s: rename \"%s\" to \"%s\": %s", __func__,  
                     temp, filename, strerror(errno));  
                 r = SSH_ERR_SYSTEM_ERROR;  
                 goto fail;  
         }  
         /* success */          /* success */
         r = 0;          r = 0;
  fail:   fail:
Line 660 
Line 664 
   
 int  int
 hostkeys_foreach(const char *path, hostkeys_foreach_fn *callback, void *ctx,  hostkeys_foreach(const char *path, hostkeys_foreach_fn *callback, void *ctx,
     const char *host, u_int options)      const char *host, const char *ip, u_int options)
 {  {
         FILE *f;          FILE *f;
         char line[8192], oline[8192];          char line[8192], oline[8192], ktype[128];
         u_long linenum = 0;          u_long linenum = 0;
         char *cp, *cp2;          char *cp, *cp2;
         u_int kbits;          u_int kbits;
           int hashed;
         int s, r = 0;          int s, r = 0;
         struct hostkey_foreach_line lineinfo;          struct hostkey_foreach_line lineinfo;
           size_t l;
   
         memset(&lineinfo, 0, sizeof(lineinfo));          memset(&lineinfo, 0, sizeof(lineinfo));
         if (host == NULL && (options & HKF_WANT_MATCH_HOST) != 0)          if (host == NULL && (options & HKF_WANT_MATCH) != 0)
                 return SSH_ERR_INVALID_ARGUMENT;                  return SSH_ERR_INVALID_ARGUMENT;
         if ((f = fopen(path, "r")) == NULL)          if ((f = fopen(path, "r")) == NULL)
                 return SSH_ERR_SYSTEM_ERROR;                  return SSH_ERR_SYSTEM_ERROR;
Line 686 
Line 692 
                 lineinfo.path = path;                  lineinfo.path = path;
                 lineinfo.linenum = linenum;                  lineinfo.linenum = linenum;
                 lineinfo.line = oline;                  lineinfo.line = oline;
                   lineinfo.marker = MRK_NONE;
                 lineinfo.status = HKF_STATUS_OK;                  lineinfo.status = HKF_STATUS_OK;
                   lineinfo.keytype = KEY_UNSPEC;
   
                 /* Skip any leading whitespace, comments and empty lines. */                  /* Skip any leading whitespace, comments and empty lines. */
                 for (cp = line; *cp == ' ' || *cp == '\t'; cp++)                  for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
                         ;                          ;
                 if (!*cp || *cp == '#' || *cp == '\n') {                  if (!*cp || *cp == '#' || *cp == '\n') {
                         if ((options & HKF_WANT_MATCH_HOST) == 0) {                          if ((options & HKF_WANT_MATCH) == 0) {
                                 lineinfo.status = HKF_STATUS_COMMENT;                                  lineinfo.status = HKF_STATUS_COMMENT;
                                 if ((r = callback(&lineinfo, ctx)) != 0)                                  if ((r = callback(&lineinfo, ctx)) != 0)
                                         break;                                          break;
Line 703 
Line 711 
                 if ((lineinfo.marker = check_markers(&cp)) == MRK_ERROR) {                  if ((lineinfo.marker = check_markers(&cp)) == MRK_ERROR) {
                         verbose("%s: invalid marker at %s:%lu",                          verbose("%s: invalid marker at %s:%lu",
                             __func__, path, linenum);                              __func__, path, linenum);
                         if ((options & HKF_WANT_MATCH_HOST) == 0)                          if ((options & HKF_WANT_MATCH) == 0)
                                 goto bad;                                  goto bad;
                         continue;                          continue;
                 }                  }
Line 716 
Line 724 
   
                 /* Check if the host name matches. */                  /* Check if the host name matches. */
                 if (host != NULL) {                  if (host != NULL) {
                         s = match_maybe_hashed(host, lineinfo.hosts,                          if ((s = match_maybe_hashed(host, lineinfo.hosts,
                             &lineinfo.was_hashed);                              &hashed)) == -1) {
                         if (s == 1)  
                                 lineinfo.status = HKF_STATUS_HOST_MATCHED;  
                         else if ((options & HKF_WANT_MATCH_HOST) != 0)  
                                 continue;  
                         else if (s == -1) {  
                                 debug2("%s: %s:%ld: bad host hash \"%.32s\"",                                  debug2("%s: %s:%ld: bad host hash \"%.32s\"",
                                     __func__, path, linenum, lineinfo.hosts);                                      __func__, path, linenum, lineinfo.hosts);
                                 goto bad;                                  goto bad;
                         }                          }
                           if (s == 1) {
                                   lineinfo.status = HKF_STATUS_MATCHED;
                                   lineinfo.match |= HKF_MATCH_HOST |
                                       (hashed ? HKF_MATCH_HOST_HASHED : 0);
                           }
                           /* Try matching IP address if supplied */
                           if (ip != NULL) {
                                   if ((s = match_maybe_hashed(ip, lineinfo.hosts,
                                       &hashed)) == -1) {
                                           debug2("%s: %s:%ld: bad ip hash "
                                               "\"%.32s\"", __func__, path,
                                               linenum, lineinfo.hosts);
                                           goto bad;
                                   }
                                   if (s == 1) {
                                           lineinfo.status = HKF_STATUS_MATCHED;
                                           lineinfo.match |= HKF_MATCH_IP |
                                               (hashed ? HKF_MATCH_IP_HASHED : 0);
                                   }
                           }
                           /*
                            * Skip this line if host matching requested and
                            * neither host nor address matched.
                            */
                           if ((options & HKF_WANT_MATCH) != 0 &&
                               lineinfo.status != HKF_STATUS_MATCHED)
                                   continue;
                 }                  }
   
                 /* Got a match.  Skip host name and any following whitespace */                  /* Got a match.  Skip host name and any following whitespace */
                 for (; *cp2 == ' ' || *cp2 == '\t'; cp2++)                  for (; *cp2 == ' ' || *cp2 == '\t'; cp2++)
                         ;                          ;
                 if (*cp2 == '\0' || *cp2 == '#') {                  if (*cp2 == '\0' || *cp2 == '#') {
                         debug2("%s:%ld: truncated before key", path, linenum);                          debug2("%s:%ld: truncated before key type",
                               path, linenum);
                         goto bad;                          goto bad;
                 }                  }
                 lineinfo.rawkey = cp = cp2;                  lineinfo.rawkey = cp = cp2;
Line 746 
Line 777 
                          */                           */
                         if ((lineinfo.key = sshkey_new(KEY_UNSPEC)) == NULL) {                          if ((lineinfo.key = sshkey_new(KEY_UNSPEC)) == NULL) {
                                 error("%s: sshkey_new failed", __func__);                                  error("%s: sshkey_new failed", __func__);
                                 return SSH_ERR_ALLOC_FAIL;                                  r = SSH_ERR_ALLOC_FAIL;
                                   break;
                         }                          }
                         if (!hostfile_read_key(&cp, &kbits, lineinfo.key)) {                          if (!hostfile_read_key(&cp, &kbits, lineinfo.key)) {
 #ifdef WITH_SSH1  #ifdef WITH_SSH1
Line 754 
Line 786 
                                 lineinfo.key = sshkey_new(KEY_RSA1);                                  lineinfo.key = sshkey_new(KEY_RSA1);
                                 if (lineinfo.key  == NULL) {                                  if (lineinfo.key  == NULL) {
                                         error("%s: sshkey_new fail", __func__);                                          error("%s: sshkey_new fail", __func__);
                                         return SSH_ERR_ALLOC_FAIL;                                          r = SSH_ERR_ALLOC_FAIL;
                                           break;
                                 }                                  }
                                 if (!hostfile_read_key(&cp, &kbits,                                  if (!hostfile_read_key(&cp, &kbits,
                                     lineinfo.key))                                      lineinfo.key))
Line 763 
Line 796 
                                 goto bad;                                  goto bad;
 #endif  #endif
                         }                          }
                         if (!hostfile_check_key(kbits, lineinfo.key, host,                          lineinfo.keytype = lineinfo.key->type;
                             path, linenum)) {                          lineinfo.comment = cp;
                   } else {
                           /* Extract and parse key type */
                           l = strcspn(lineinfo.rawkey, " \t");
                           if (l <= 1 || l >= sizeof(ktype) ||
                               lineinfo.rawkey[l] == '\0')
                                   goto bad;
                           memcpy(ktype, lineinfo.rawkey, l);
                           ktype[l] = '\0';
                           lineinfo.keytype = sshkey_type_from_name(ktype);
   #ifdef WITH_SSH1
                           /*
                            * Assume RSA1 if the first component is a short
                            * decimal number.
                            */
                           if (lineinfo.keytype == KEY_UNSPEC && l < 8 &&
                               strspn(ktype, "0123456789") == l)
                                   lineinfo.keytype = KEY_RSA1;
   #endif
                           /*
                            * Check that something other than whitespace follows
                            * the key type. This won't catch all corruption, but
                            * it does catch trivial truncation.
                            */
                           cp2 += l; /* Skip past key type */
                           for (; *cp2 == ' ' || *cp2 == '\t'; cp2++)
                                   ;
                           if (*cp2 == '\0' || *cp2 == '#') {
                                   debug2("%s:%ld: truncated after key type",
                                       path, linenum);
                                   lineinfo.keytype = KEY_UNSPEC;
                           }
                           if (lineinfo.keytype == KEY_UNSPEC) {
  bad:   bad:
                                   sshkey_free(lineinfo.key);
                                   lineinfo.key = NULL;
                                 lineinfo.status = HKF_STATUS_INVALID;                                  lineinfo.status = HKF_STATUS_INVALID;
                                 if ((r = callback(&lineinfo, ctx)) != 0)                                  if ((r = callback(&lineinfo, ctx)) != 0)
                                         break;                                          break;

Legend:
Removed from v.1.63  
changed lines
  Added in v.1.64