diff options
Diffstat (limited to 'hostfile.c')
-rw-r--r-- | hostfile.c | 219 |
1 files changed, 143 insertions, 76 deletions
diff --git a/hostfile.c b/hostfile.c index ea6bc6fc8..b235795e6 100644 --- a/hostfile.c +++ b/hostfile.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: hostfile.c,v 1.63 2015/01/26 13:36:53 djm Exp $ */ | 1 | /* $OpenBSD: hostfile.c,v 1.64 2015/02/16 22:08:57 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -184,24 +184,6 @@ hostfile_read_key(char **cpp, u_int *bitsp, struct sshkey *ret) | |||
184 | return 1; | 184 | return 1; |
185 | } | 185 | } |
186 | 186 | ||
187 | static int | ||
188 | hostfile_check_key(int bits, const struct sshkey *key, const char *host, | ||
189 | const char *filename, u_long linenum) | ||
190 | { | ||
191 | #ifdef WITH_SSH1 | ||
192 | if (key == NULL || key->type != KEY_RSA1 || key->rsa == NULL) | ||
193 | return 1; | ||
194 | if (bits != BN_num_bits(key->rsa->n)) { | ||
195 | logit("Warning: %s, line %lu: keysize mismatch for host %s: " | ||
196 | "actual %d vs. announced %d.", | ||
197 | filename, linenum, host, BN_num_bits(key->rsa->n), bits); | ||
198 | logit("Warning: replace %d with %d in %s, line %lu.", | ||
199 | bits, BN_num_bits(key->rsa->n), filename, linenum); | ||
200 | } | ||
201 | #endif | ||
202 | return 1; | ||
203 | } | ||
204 | |||
205 | static HostkeyMarker | 187 | static HostkeyMarker |
206 | check_markers(char **cpp) | 188 | check_markers(char **cpp) |
207 | { | 189 | { |
@@ -295,8 +277,8 @@ load_hostkeys(struct hostkeys *hostkeys, const char *host, const char *path) | |||
295 | ctx.num_loaded = 0; | 277 | ctx.num_loaded = 0; |
296 | ctx.hostkeys = hostkeys; | 278 | ctx.hostkeys = hostkeys; |
297 | 279 | ||
298 | if ((r = hostkeys_foreach(path, record_hostkey, &ctx, host, | 280 | if ((r = hostkeys_foreach(path, record_hostkey, &ctx, host, NULL, |
299 | HKF_WANT_MATCH_HOST|HKF_WANT_PARSE_KEY)) != 0) { | 281 | HKF_WANT_MATCH|HKF_WANT_PARSE_KEY)) != 0) { |
300 | if (r != SSH_ERR_SYSTEM_ERROR && errno != ENOENT) | 282 | if (r != SSH_ERR_SYSTEM_ERROR && errno != ENOENT) |
301 | debug("%s: hostkeys_foreach failed for %s: %s", | 283 | debug("%s: hostkeys_foreach failed for %s: %s", |
302 | __func__, path, ssh_err(r)); | 284 | __func__, path, ssh_err(r)); |
@@ -433,7 +415,7 @@ lookup_key_in_hostkeys_by_type(struct hostkeys *hostkeys, int keytype, | |||
433 | } | 415 | } |
434 | 416 | ||
435 | static int | 417 | static int |
436 | write_host_entry(FILE *f, const char *host, | 418 | write_host_entry(FILE *f, const char *host, const char *ip, |
437 | const struct sshkey *key, int store_hash) | 419 | const struct sshkey *key, int store_hash) |
438 | { | 420 | { |
439 | int r, success = 0; | 421 | int r, success = 0; |
@@ -444,8 +426,11 @@ write_host_entry(FILE *f, const char *host, | |||
444 | error("%s: host_hash failed", __func__); | 426 | error("%s: host_hash failed", __func__); |
445 | return 0; | 427 | return 0; |
446 | } | 428 | } |
447 | } | 429 | fprintf(f, "%s ", hashed_host); |
448 | fprintf(f, "%s ", store_hash ? hashed_host : host); | 430 | } else if (ip != NULL) |
431 | fprintf(f, "%s,%s ", host, ip); | ||
432 | else | ||
433 | fprintf(f, "%s ", host); | ||
449 | 434 | ||
450 | if ((r = sshkey_write(key, f)) == 0) | 435 | if ((r = sshkey_write(key, f)) == 0) |
451 | success = 1; | 436 | success = 1; |
@@ -471,7 +456,7 @@ add_host_to_hostfile(const char *filename, const char *host, | |||
471 | f = fopen(filename, "a"); | 456 | f = fopen(filename, "a"); |
472 | if (!f) | 457 | if (!f) |
473 | return 0; | 458 | return 0; |
474 | success = write_host_entry(f, host, key, store_hash); | 459 | success = write_host_entry(f, host, NULL, key, store_hash); |
475 | fclose(f); | 460 | fclose(f); |
476 | return success; | 461 | return success; |
477 | } | 462 | } |
@@ -480,19 +465,20 @@ struct host_delete_ctx { | |||
480 | FILE *out; | 465 | FILE *out; |
481 | int quiet; | 466 | int quiet; |
482 | const char *host; | 467 | const char *host; |
483 | int *skip_keys; | 468 | int *skip_keys; /* XXX split for host/ip? might want to ensure both */ |
484 | struct sshkey * const *keys; | 469 | struct sshkey * const *keys; |
485 | size_t nkeys; | 470 | size_t nkeys; |
471 | int modified; | ||
486 | }; | 472 | }; |
487 | 473 | ||
488 | static int | 474 | static int |
489 | host_delete(struct hostkey_foreach_line *l, void *_ctx) | 475 | host_delete(struct hostkey_foreach_line *l, void *_ctx) |
490 | { | 476 | { |
491 | struct host_delete_ctx *ctx = (struct host_delete_ctx *)_ctx; | 477 | struct host_delete_ctx *ctx = (struct host_delete_ctx *)_ctx; |
492 | int loglevel = ctx->quiet ? SYSLOG_LEVEL_DEBUG1 : SYSLOG_LEVEL_INFO; | 478 | int loglevel = ctx->quiet ? SYSLOG_LEVEL_DEBUG1 : SYSLOG_LEVEL_VERBOSE; |
493 | size_t i; | 479 | size_t i; |
494 | 480 | ||
495 | if (l->status == HKF_STATUS_HOST_MATCHED) { | 481 | if (l->status == HKF_STATUS_MATCHED) { |
496 | if (l->marker != MRK_NONE) { | 482 | if (l->marker != MRK_NONE) { |
497 | /* Don't remove CA and revocation lines */ | 483 | /* Don't remove CA and revocation lines */ |
498 | fprintf(ctx->out, "%s\n", l->line); | 484 | fprintf(ctx->out, "%s\n", l->line); |
@@ -525,9 +511,10 @@ host_delete(struct hostkey_foreach_line *l, void *_ctx) | |||
525 | * Hostname matches and has no CA/revoke marker, delete it | 511 | * Hostname matches and has no CA/revoke marker, delete it |
526 | * by *not* writing the line to ctx->out. | 512 | * by *not* writing the line to ctx->out. |
527 | */ | 513 | */ |
528 | do_log2(loglevel, "%s%s%s:%ld: Host %s removed", | 514 | do_log2(loglevel, "%s%s%s:%ld: Removed %s key for host %s", |
529 | ctx->quiet ? __func__ : "", ctx->quiet ? ": " : "", | 515 | ctx->quiet ? __func__ : "", ctx->quiet ? ": " : "", |
530 | l->path, l->linenum, ctx->host); | 516 | l->path, l->linenum, sshkey_type(l->key), ctx->host); |
517 | ctx->modified = 1; | ||
531 | return 0; | 518 | return 0; |
532 | } | 519 | } |
533 | /* Retain non-matching hosts and invalid lines when deleting */ | 520 | /* Retain non-matching hosts and invalid lines when deleting */ |
@@ -541,13 +528,13 @@ host_delete(struct hostkey_foreach_line *l, void *_ctx) | |||
541 | } | 528 | } |
542 | 529 | ||
543 | int | 530 | int |
544 | hostfile_replace_entries(const char *filename, const char *host, | 531 | hostfile_replace_entries(const char *filename, const char *host, const char *ip, |
545 | struct sshkey **keys, size_t nkeys, int store_hash, int quiet) | 532 | struct sshkey **keys, size_t nkeys, int store_hash, int quiet, int hash_alg) |
546 | { | 533 | { |
547 | int r, fd, oerrno = 0; | 534 | int r, fd, oerrno = 0; |
548 | int loglevel = quiet ? SYSLOG_LEVEL_DEBUG1 : SYSLOG_LEVEL_INFO; | 535 | int loglevel = quiet ? SYSLOG_LEVEL_DEBUG1 : SYSLOG_LEVEL_VERBOSE; |
549 | struct host_delete_ctx ctx; | 536 | struct host_delete_ctx ctx; |
550 | char *temp = NULL, *back = NULL; | 537 | char *fp, *temp = NULL, *back = NULL; |
551 | mode_t omask; | 538 | mode_t omask; |
552 | size_t i; | 539 | size_t i; |
553 | 540 | ||
@@ -560,6 +547,7 @@ hostfile_replace_entries(const char *filename, const char *host, | |||
560 | return SSH_ERR_ALLOC_FAIL; | 547 | return SSH_ERR_ALLOC_FAIL; |
561 | ctx.keys = keys; | 548 | ctx.keys = keys; |
562 | ctx.nkeys = nkeys; | 549 | ctx.nkeys = nkeys; |
550 | ctx.modified = 0; | ||
563 | 551 | ||
564 | /* | 552 | /* |
565 | * Prepare temporary file for in-place deletion. | 553 | * Prepare temporary file for in-place deletion. |
@@ -585,7 +573,7 @@ hostfile_replace_entries(const char *filename, const char *host, | |||
585 | } | 573 | } |
586 | 574 | ||
587 | /* Remove all entries for the specified host from the file */ | 575 | /* Remove all entries for the specified host from the file */ |
588 | if ((r = hostkeys_foreach(filename, host_delete, &ctx, host, | 576 | if ((r = hostkeys_foreach(filename, host_delete, &ctx, host, ip, |
589 | HKF_WANT_PARSE_KEY)) != 0) { | 577 | HKF_WANT_PARSE_KEY)) != 0) { |
590 | error("%s: hostkeys_foreach failed: %s", __func__, ssh_err(r)); | 578 | error("%s: hostkeys_foreach failed: %s", __func__, ssh_err(r)); |
591 | goto fail; | 579 | goto fail; |
@@ -595,38 +583,54 @@ hostfile_replace_entries(const char *filename, const char *host, | |||
595 | for (i = 0; i < nkeys; i++) { | 583 | for (i = 0; i < nkeys; i++) { |
596 | if (ctx.skip_keys[i]) | 584 | if (ctx.skip_keys[i]) |
597 | continue; | 585 | continue; |
598 | do_log2(loglevel, "%s%sadd %s key to %s", | 586 | if ((fp = sshkey_fingerprint(keys[i], hash_alg, |
599 | quiet ? __func__ : "", quiet ? ": " : NULL, | 587 | SSH_FP_DEFAULT)) == NULL) { |
600 | sshkey_type(keys[i]), filename); | 588 | r = SSH_ERR_ALLOC_FAIL; |
601 | if (!write_host_entry(ctx.out, host, keys[i], store_hash)) { | 589 | goto fail; |
590 | } | ||
591 | do_log2(loglevel, "%s%sAdding new key for %s to %s: %s %s", | ||
592 | quiet ? __func__ : "", quiet ? ": " : "", host, filename, | ||
593 | sshkey_ssh_name(keys[i]), fp); | ||
594 | free(fp); | ||
595 | if (!write_host_entry(ctx.out, host, ip, keys[i], store_hash)) { | ||
602 | r = SSH_ERR_INTERNAL_ERROR; | 596 | r = SSH_ERR_INTERNAL_ERROR; |
603 | goto fail; | 597 | goto fail; |
604 | } | 598 | } |
599 | ctx.modified = 1; | ||
605 | } | 600 | } |
606 | fclose(ctx.out); | 601 | fclose(ctx.out); |
607 | ctx.out = NULL; | 602 | ctx.out = NULL; |
608 | 603 | ||
609 | /* Backup the original file and replace it with the temporary */ | 604 | if (ctx.modified) { |
610 | if (unlink(back) == -1 && errno != ENOENT) { | 605 | /* Backup the original file and replace it with the temporary */ |
611 | oerrno = errno; | 606 | if (unlink(back) == -1 && errno != ENOENT) { |
612 | error("%s: unlink %.100s: %s", __func__, back, strerror(errno)); | 607 | oerrno = errno; |
613 | r = SSH_ERR_SYSTEM_ERROR; | 608 | error("%s: unlink %.100s: %s", __func__, |
614 | goto fail; | 609 | back, strerror(errno)); |
615 | } | 610 | r = SSH_ERR_SYSTEM_ERROR; |
616 | if (link(filename, back) == -1) { | 611 | goto fail; |
617 | oerrno = errno; | 612 | } |
618 | error("%s: link %.100s to %.100s: %s", __func__, filename, back, | 613 | if (link(filename, back) == -1) { |
619 | strerror(errno)); | 614 | oerrno = errno; |
620 | r = SSH_ERR_SYSTEM_ERROR; | 615 | error("%s: link %.100s to %.100s: %s", __func__, |
621 | goto fail; | 616 | filename, back, strerror(errno)); |
622 | } | 617 | r = SSH_ERR_SYSTEM_ERROR; |
623 | if (rename(temp, filename) == -1) { | 618 | goto fail; |
624 | oerrno = errno; | 619 | } |
625 | error("%s: rename \"%s\" to \"%s\": %s", __func__, | 620 | if (rename(temp, filename) == -1) { |
626 | temp, filename, strerror(errno)); | 621 | oerrno = errno; |
627 | r = SSH_ERR_SYSTEM_ERROR; | 622 | error("%s: rename \"%s\" to \"%s\": %s", __func__, |
628 | goto fail; | 623 | temp, filename, strerror(errno)); |
624 | r = SSH_ERR_SYSTEM_ERROR; | ||
625 | goto fail; | ||
626 | } | ||
627 | } else { | ||
628 | /* No changes made; just delete the temporary file */ | ||
629 | if (unlink(temp) != 0) | ||
630 | error("%s: unlink \"%s\": %s", __func__, | ||
631 | temp, strerror(errno)); | ||
629 | } | 632 | } |
633 | |||
630 | /* success */ | 634 | /* success */ |
631 | r = 0; | 635 | r = 0; |
632 | fail: | 636 | fail: |
@@ -663,18 +667,20 @@ match_maybe_hashed(const char *host, const char *names, int *was_hashed) | |||
663 | 667 | ||
664 | int | 668 | int |
665 | hostkeys_foreach(const char *path, hostkeys_foreach_fn *callback, void *ctx, | 669 | hostkeys_foreach(const char *path, hostkeys_foreach_fn *callback, void *ctx, |
666 | const char *host, u_int options) | 670 | const char *host, const char *ip, u_int options) |
667 | { | 671 | { |
668 | FILE *f; | 672 | FILE *f; |
669 | char line[8192], oline[8192]; | 673 | char line[8192], oline[8192], ktype[128]; |
670 | u_long linenum = 0; | 674 | u_long linenum = 0; |
671 | char *cp, *cp2; | 675 | char *cp, *cp2; |
672 | u_int kbits; | 676 | u_int kbits; |
677 | int hashed; | ||
673 | int s, r = 0; | 678 | int s, r = 0; |
674 | struct hostkey_foreach_line lineinfo; | 679 | struct hostkey_foreach_line lineinfo; |
680 | size_t l; | ||
675 | 681 | ||
676 | memset(&lineinfo, 0, sizeof(lineinfo)); | 682 | memset(&lineinfo, 0, sizeof(lineinfo)); |
677 | if (host == NULL && (options & HKF_WANT_MATCH_HOST) != 0) | 683 | if (host == NULL && (options & HKF_WANT_MATCH) != 0) |
678 | return SSH_ERR_INVALID_ARGUMENT; | 684 | return SSH_ERR_INVALID_ARGUMENT; |
679 | if ((f = fopen(path, "r")) == NULL) | 685 | if ((f = fopen(path, "r")) == NULL) |
680 | return SSH_ERR_SYSTEM_ERROR; | 686 | return SSH_ERR_SYSTEM_ERROR; |
@@ -689,13 +695,15 @@ hostkeys_foreach(const char *path, hostkeys_foreach_fn *callback, void *ctx, | |||
689 | lineinfo.path = path; | 695 | lineinfo.path = path; |
690 | lineinfo.linenum = linenum; | 696 | lineinfo.linenum = linenum; |
691 | lineinfo.line = oline; | 697 | lineinfo.line = oline; |
698 | lineinfo.marker = MRK_NONE; | ||
692 | lineinfo.status = HKF_STATUS_OK; | 699 | lineinfo.status = HKF_STATUS_OK; |
700 | lineinfo.keytype = KEY_UNSPEC; | ||
693 | 701 | ||
694 | /* Skip any leading whitespace, comments and empty lines. */ | 702 | /* Skip any leading whitespace, comments and empty lines. */ |
695 | for (cp = line; *cp == ' ' || *cp == '\t'; cp++) | 703 | for (cp = line; *cp == ' ' || *cp == '\t'; cp++) |
696 | ; | 704 | ; |
697 | if (!*cp || *cp == '#' || *cp == '\n') { | 705 | if (!*cp || *cp == '#' || *cp == '\n') { |
698 | if ((options & HKF_WANT_MATCH_HOST) == 0) { | 706 | if ((options & HKF_WANT_MATCH) == 0) { |
699 | lineinfo.status = HKF_STATUS_COMMENT; | 707 | lineinfo.status = HKF_STATUS_COMMENT; |
700 | if ((r = callback(&lineinfo, ctx)) != 0) | 708 | if ((r = callback(&lineinfo, ctx)) != 0) |
701 | break; | 709 | break; |
@@ -706,7 +714,7 @@ hostkeys_foreach(const char *path, hostkeys_foreach_fn *callback, void *ctx, | |||
706 | if ((lineinfo.marker = check_markers(&cp)) == MRK_ERROR) { | 714 | if ((lineinfo.marker = check_markers(&cp)) == MRK_ERROR) { |
707 | verbose("%s: invalid marker at %s:%lu", | 715 | verbose("%s: invalid marker at %s:%lu", |
708 | __func__, path, linenum); | 716 | __func__, path, linenum); |
709 | if ((options & HKF_WANT_MATCH_HOST) == 0) | 717 | if ((options & HKF_WANT_MATCH) == 0) |
710 | goto bad; | 718 | goto bad; |
711 | continue; | 719 | continue; |
712 | } | 720 | } |
@@ -719,24 +727,47 @@ hostkeys_foreach(const char *path, hostkeys_foreach_fn *callback, void *ctx, | |||
719 | 727 | ||
720 | /* Check if the host name matches. */ | 728 | /* Check if the host name matches. */ |
721 | if (host != NULL) { | 729 | if (host != NULL) { |
722 | s = match_maybe_hashed(host, lineinfo.hosts, | 730 | if ((s = match_maybe_hashed(host, lineinfo.hosts, |
723 | &lineinfo.was_hashed); | 731 | &hashed)) == -1) { |
724 | if (s == 1) | ||
725 | lineinfo.status = HKF_STATUS_HOST_MATCHED; | ||
726 | else if ((options & HKF_WANT_MATCH_HOST) != 0) | ||
727 | continue; | ||
728 | else if (s == -1) { | ||
729 | debug2("%s: %s:%ld: bad host hash \"%.32s\"", | 732 | debug2("%s: %s:%ld: bad host hash \"%.32s\"", |
730 | __func__, path, linenum, lineinfo.hosts); | 733 | __func__, path, linenum, lineinfo.hosts); |
731 | goto bad; | 734 | goto bad; |
732 | } | 735 | } |
736 | if (s == 1) { | ||
737 | lineinfo.status = HKF_STATUS_MATCHED; | ||
738 | lineinfo.match |= HKF_MATCH_HOST | | ||
739 | (hashed ? HKF_MATCH_HOST_HASHED : 0); | ||
740 | } | ||
741 | /* Try matching IP address if supplied */ | ||
742 | if (ip != NULL) { | ||
743 | if ((s = match_maybe_hashed(ip, lineinfo.hosts, | ||
744 | &hashed)) == -1) { | ||
745 | debug2("%s: %s:%ld: bad ip hash " | ||
746 | "\"%.32s\"", __func__, path, | ||
747 | linenum, lineinfo.hosts); | ||
748 | goto bad; | ||
749 | } | ||
750 | if (s == 1) { | ||
751 | lineinfo.status = HKF_STATUS_MATCHED; | ||
752 | lineinfo.match |= HKF_MATCH_IP | | ||
753 | (hashed ? HKF_MATCH_IP_HASHED : 0); | ||
754 | } | ||
755 | } | ||
756 | /* | ||
757 | * Skip this line if host matching requested and | ||
758 | * neither host nor address matched. | ||
759 | */ | ||
760 | if ((options & HKF_WANT_MATCH) != 0 && | ||
761 | lineinfo.status != HKF_STATUS_MATCHED) | ||
762 | continue; | ||
733 | } | 763 | } |
734 | 764 | ||
735 | /* Got a match. Skip host name and any following whitespace */ | 765 | /* Got a match. Skip host name and any following whitespace */ |
736 | for (; *cp2 == ' ' || *cp2 == '\t'; cp2++) | 766 | for (; *cp2 == ' ' || *cp2 == '\t'; cp2++) |
737 | ; | 767 | ; |
738 | if (*cp2 == '\0' || *cp2 == '#') { | 768 | if (*cp2 == '\0' || *cp2 == '#') { |
739 | debug2("%s:%ld: truncated before key", path, linenum); | 769 | debug2("%s:%ld: truncated before key type", |
770 | path, linenum); | ||
740 | goto bad; | 771 | goto bad; |
741 | } | 772 | } |
742 | lineinfo.rawkey = cp = cp2; | 773 | lineinfo.rawkey = cp = cp2; |
@@ -749,7 +780,8 @@ hostkeys_foreach(const char *path, hostkeys_foreach_fn *callback, void *ctx, | |||
749 | */ | 780 | */ |
750 | if ((lineinfo.key = sshkey_new(KEY_UNSPEC)) == NULL) { | 781 | if ((lineinfo.key = sshkey_new(KEY_UNSPEC)) == NULL) { |
751 | error("%s: sshkey_new failed", __func__); | 782 | error("%s: sshkey_new failed", __func__); |
752 | return SSH_ERR_ALLOC_FAIL; | 783 | r = SSH_ERR_ALLOC_FAIL; |
784 | break; | ||
753 | } | 785 | } |
754 | if (!hostfile_read_key(&cp, &kbits, lineinfo.key)) { | 786 | if (!hostfile_read_key(&cp, &kbits, lineinfo.key)) { |
755 | #ifdef WITH_SSH1 | 787 | #ifdef WITH_SSH1 |
@@ -757,7 +789,8 @@ hostkeys_foreach(const char *path, hostkeys_foreach_fn *callback, void *ctx, | |||
757 | lineinfo.key = sshkey_new(KEY_RSA1); | 789 | lineinfo.key = sshkey_new(KEY_RSA1); |
758 | if (lineinfo.key == NULL) { | 790 | if (lineinfo.key == NULL) { |
759 | error("%s: sshkey_new fail", __func__); | 791 | error("%s: sshkey_new fail", __func__); |
760 | return SSH_ERR_ALLOC_FAIL; | 792 | r = SSH_ERR_ALLOC_FAIL; |
793 | break; | ||
761 | } | 794 | } |
762 | if (!hostfile_read_key(&cp, &kbits, | 795 | if (!hostfile_read_key(&cp, &kbits, |
763 | lineinfo.key)) | 796 | lineinfo.key)) |
@@ -766,9 +799,43 @@ hostkeys_foreach(const char *path, hostkeys_foreach_fn *callback, void *ctx, | |||
766 | goto bad; | 799 | goto bad; |
767 | #endif | 800 | #endif |
768 | } | 801 | } |
769 | if (!hostfile_check_key(kbits, lineinfo.key, host, | 802 | lineinfo.keytype = lineinfo.key->type; |
770 | path, linenum)) { | 803 | lineinfo.comment = cp; |
804 | } else { | ||
805 | /* Extract and parse key type */ | ||
806 | l = strcspn(lineinfo.rawkey, " \t"); | ||
807 | if (l <= 1 || l >= sizeof(ktype) || | ||
808 | lineinfo.rawkey[l] == '\0') | ||
809 | goto bad; | ||
810 | memcpy(ktype, lineinfo.rawkey, l); | ||
811 | ktype[l] = '\0'; | ||
812 | lineinfo.keytype = sshkey_type_from_name(ktype); | ||
813 | #ifdef WITH_SSH1 | ||
814 | /* | ||
815 | * Assume RSA1 if the first component is a short | ||
816 | * decimal number. | ||
817 | */ | ||
818 | if (lineinfo.keytype == KEY_UNSPEC && l < 8 && | ||
819 | strspn(ktype, "0123456789") == l) | ||
820 | lineinfo.keytype = KEY_RSA1; | ||
821 | #endif | ||
822 | /* | ||
823 | * Check that something other than whitespace follows | ||
824 | * the key type. This won't catch all corruption, but | ||
825 | * it does catch trivial truncation. | ||
826 | */ | ||
827 | cp2 += l; /* Skip past key type */ | ||
828 | for (; *cp2 == ' ' || *cp2 == '\t'; cp2++) | ||
829 | ; | ||
830 | if (*cp2 == '\0' || *cp2 == '#') { | ||
831 | debug2("%s:%ld: truncated after key type", | ||
832 | path, linenum); | ||
833 | lineinfo.keytype = KEY_UNSPEC; | ||
834 | } | ||
835 | if (lineinfo.keytype == KEY_UNSPEC) { | ||
771 | bad: | 836 | bad: |
837 | sshkey_free(lineinfo.key); | ||
838 | lineinfo.key = NULL; | ||
772 | lineinfo.status = HKF_STATUS_INVALID; | 839 | lineinfo.status = HKF_STATUS_INVALID; |
773 | if ((r = callback(&lineinfo, ctx)) != 0) | 840 | if ((r = callback(&lineinfo, ctx)) != 0) |
774 | break; | 841 | break; |