diff options
Diffstat (limited to 'ssh-keygen.c')
-rw-r--r-- | ssh-keygen.c | 236 |
1 files changed, 226 insertions, 10 deletions
diff --git a/ssh-keygen.c b/ssh-keygen.c index d39e7d881..a9931d4d8 100644 --- a/ssh-keygen.c +++ b/ssh-keygen.c | |||
@@ -12,7 +12,7 @@ | |||
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include "includes.h" | 14 | #include "includes.h" |
15 | RCSID("$OpenBSD: ssh-keygen.c,v 1.117 2004/07/11 17:48:47 deraadt Exp $"); | 15 | RCSID("$OpenBSD: ssh-keygen.c,v 1.120 2005/03/02 01:27:41 djm Exp $"); |
16 | 16 | ||
17 | #include <openssl/evp.h> | 17 | #include <openssl/evp.h> |
18 | #include <openssl/pem.h> | 18 | #include <openssl/pem.h> |
@@ -27,6 +27,8 @@ RCSID("$OpenBSD: ssh-keygen.c,v 1.117 2004/07/11 17:48:47 deraadt Exp $"); | |||
27 | #include "pathnames.h" | 27 | #include "pathnames.h" |
28 | #include "log.h" | 28 | #include "log.h" |
29 | #include "misc.h" | 29 | #include "misc.h" |
30 | #include "match.h" | ||
31 | #include "hostfile.h" | ||
30 | 32 | ||
31 | #ifdef SMARTCARD | 33 | #ifdef SMARTCARD |
32 | #include "scard.h" | 34 | #include "scard.h" |
@@ -50,6 +52,13 @@ int change_comment = 0; | |||
50 | 52 | ||
51 | int quiet = 0; | 53 | int quiet = 0; |
52 | 54 | ||
55 | /* Flag indicating that we want to hash a known_hosts file */ | ||
56 | int hash_hosts = 0; | ||
57 | /* Flag indicating that we want lookup a host in known_hosts file */ | ||
58 | int find_host = 0; | ||
59 | /* Flag indicating that we want to delete a host from a known_hosts file */ | ||
60 | int delete_host = 0; | ||
61 | |||
53 | /* Flag indicating that we just want to see the key fingerprint */ | 62 | /* Flag indicating that we just want to see the key fingerprint */ |
54 | int print_fingerprint = 0; | 63 | int print_fingerprint = 0; |
55 | int print_bubblebabble = 0; | 64 | int print_bubblebabble = 0; |
@@ -239,6 +248,7 @@ do_convert_private_ssh2_from_blob(u_char *blob, u_int blen) | |||
239 | } else if (strstr(type, "rsa")) { | 248 | } else if (strstr(type, "rsa")) { |
240 | ktype = KEY_RSA; | 249 | ktype = KEY_RSA; |
241 | } else { | 250 | } else { |
251 | buffer_free(&b); | ||
242 | xfree(type); | 252 | xfree(type); |
243 | return NULL; | 253 | return NULL; |
244 | } | 254 | } |
@@ -540,6 +550,201 @@ do_fingerprint(struct passwd *pw) | |||
540 | exit(0); | 550 | exit(0); |
541 | } | 551 | } |
542 | 552 | ||
553 | static void | ||
554 | print_host(FILE *f, char *name, Key *public, int hash) | ||
555 | { | ||
556 | if (hash && (name = host_hash(name, NULL, 0)) == NULL) | ||
557 | fatal("hash_host failed"); | ||
558 | fprintf(f, "%s ", name); | ||
559 | if (!key_write(public, f)) | ||
560 | fatal("key_write failed"); | ||
561 | fprintf(f, "\n"); | ||
562 | } | ||
563 | |||
564 | static void | ||
565 | do_known_hosts(struct passwd *pw, const char *name) | ||
566 | { | ||
567 | FILE *in, *out = stdout; | ||
568 | Key *public; | ||
569 | char *cp, *cp2, *kp, *kp2; | ||
570 | char line[16*1024], tmp[MAXPATHLEN], old[MAXPATHLEN]; | ||
571 | int c, i, skip = 0, inplace = 0, num = 0, invalid = 0, has_unhashed = 0; | ||
572 | |||
573 | if (!have_identity) { | ||
574 | cp = tilde_expand_filename(_PATH_SSH_USER_HOSTFILE, pw->pw_uid); | ||
575 | if (strlcpy(identity_file, cp, sizeof(identity_file)) >= | ||
576 | sizeof(identity_file)) | ||
577 | fatal("Specified known hosts path too long"); | ||
578 | xfree(cp); | ||
579 | have_identity = 1; | ||
580 | } | ||
581 | if ((in = fopen(identity_file, "r")) == NULL) | ||
582 | fatal("fopen: %s", strerror(errno)); | ||
583 | |||
584 | /* | ||
585 | * Find hosts goes to stdout, hash and deletions happen in-place | ||
586 | * A corner case is ssh-keygen -HF foo, which should go to stdout | ||
587 | */ | ||
588 | if (!find_host && (hash_hosts || delete_host)) { | ||
589 | if (strlcpy(tmp, identity_file, sizeof(tmp)) >= sizeof(tmp) || | ||
590 | strlcat(tmp, ".XXXXXXXXXX", sizeof(tmp)) >= sizeof(tmp) || | ||
591 | strlcpy(old, identity_file, sizeof(old)) >= sizeof(old) || | ||
592 | strlcat(old, ".old", sizeof(old)) >= sizeof(old)) | ||
593 | fatal("known_hosts path too long"); | ||
594 | umask(077); | ||
595 | if ((c = mkstemp(tmp)) == -1) | ||
596 | fatal("mkstemp: %s", strerror(errno)); | ||
597 | if ((out = fdopen(c, "w")) == NULL) { | ||
598 | c = errno; | ||
599 | unlink(tmp); | ||
600 | fatal("fdopen: %s", strerror(c)); | ||
601 | } | ||
602 | inplace = 1; | ||
603 | } | ||
604 | |||
605 | while (fgets(line, sizeof(line), in)) { | ||
606 | num++; | ||
607 | i = strlen(line) - 1; | ||
608 | if (line[i] != '\n') { | ||
609 | error("line %d too long: %.40s...", num, line); | ||
610 | skip = 1; | ||
611 | invalid = 1; | ||
612 | continue; | ||
613 | } | ||
614 | if (skip) { | ||
615 | skip = 0; | ||
616 | continue; | ||
617 | } | ||
618 | line[i] = '\0'; | ||
619 | |||
620 | /* Skip leading whitespace, empty and comment lines. */ | ||
621 | for (cp = line; *cp == ' ' || *cp == '\t'; cp++) | ||
622 | ; | ||
623 | if (!*cp || *cp == '\n' || *cp == '#') { | ||
624 | if (inplace) | ||
625 | fprintf(out, "%s\n", cp); | ||
626 | continue; | ||
627 | } | ||
628 | /* Find the end of the host name portion. */ | ||
629 | for (kp = cp; *kp && *kp != ' ' && *kp != '\t'; kp++) | ||
630 | ; | ||
631 | if (*kp == '\0' || *(kp + 1) == '\0') { | ||
632 | error("line %d missing key: %.40s...", | ||
633 | num, line); | ||
634 | invalid = 1; | ||
635 | continue; | ||
636 | } | ||
637 | *kp++ = '\0'; | ||
638 | kp2 = kp; | ||
639 | |||
640 | public = key_new(KEY_RSA1); | ||
641 | if (key_read(public, &kp) != 1) { | ||
642 | kp = kp2; | ||
643 | key_free(public); | ||
644 | public = key_new(KEY_UNSPEC); | ||
645 | if (key_read(public, &kp) != 1) { | ||
646 | error("line %d invalid key: %.40s...", | ||
647 | num, line); | ||
648 | key_free(public); | ||
649 | invalid = 1; | ||
650 | continue; | ||
651 | } | ||
652 | } | ||
653 | |||
654 | if (*cp == HASH_DELIM) { | ||
655 | if (find_host || delete_host) { | ||
656 | cp2 = host_hash(name, cp, strlen(cp)); | ||
657 | if (cp2 == NULL) { | ||
658 | error("line %d: invalid hashed " | ||
659 | "name: %.64s...", num, line); | ||
660 | invalid = 1; | ||
661 | continue; | ||
662 | } | ||
663 | c = (strcmp(cp2, cp) == 0); | ||
664 | if (find_host && c) { | ||
665 | printf("# Host %s found: " | ||
666 | "line %d type %s\n", name, | ||
667 | num, key_type(public)); | ||
668 | print_host(out, cp, public, 0); | ||
669 | } | ||
670 | if (delete_host && !c) | ||
671 | print_host(out, cp, public, 0); | ||
672 | } else if (hash_hosts) | ||
673 | print_host(out, cp, public, 0); | ||
674 | } else { | ||
675 | if (find_host || delete_host) { | ||
676 | c = (match_hostname(name, cp, | ||
677 | strlen(cp)) == 1); | ||
678 | if (find_host && c) { | ||
679 | printf("# Host %s found: " | ||
680 | "line %d type %s\n", name, | ||
681 | num, key_type(public)); | ||
682 | print_host(out, cp, public, hash_hosts); | ||
683 | } | ||
684 | if (delete_host && !c) | ||
685 | print_host(out, cp, public, 0); | ||
686 | } else if (hash_hosts) { | ||
687 | for(cp2 = strsep(&cp, ","); | ||
688 | cp2 != NULL && *cp2 != '\0'; | ||
689 | cp2 = strsep(&cp, ",")) { | ||
690 | if (strcspn(cp2, "*?!") != strlen(cp2)) | ||
691 | fprintf(stderr, "Warning: " | ||
692 | "ignoring host name with " | ||
693 | "metacharacters: %.64s\n", | ||
694 | cp2); | ||
695 | else | ||
696 | print_host(out, cp2, public, 1); | ||
697 | } | ||
698 | has_unhashed = 1; | ||
699 | } | ||
700 | } | ||
701 | key_free(public); | ||
702 | } | ||
703 | fclose(in); | ||
704 | |||
705 | if (invalid) { | ||
706 | fprintf(stderr, "%s is not a valid known_host file.\n", | ||
707 | identity_file); | ||
708 | if (inplace) { | ||
709 | fprintf(stderr, "Not replacing existing known_hosts " | ||
710 | "file beacuse of errors"); | ||
711 | fclose(out); | ||
712 | unlink(tmp); | ||
713 | } | ||
714 | exit(1); | ||
715 | } | ||
716 | |||
717 | if (inplace) { | ||
718 | fclose(out); | ||
719 | |||
720 | /* Backup existing file */ | ||
721 | if (unlink(old) == -1 && errno != ENOENT) | ||
722 | fatal("unlink %.100s: %s", old, strerror(errno)); | ||
723 | if (link(identity_file, old) == -1) | ||
724 | fatal("link %.100s to %.100s: %s", identity_file, old, | ||
725 | strerror(errno)); | ||
726 | /* Move new one into place */ | ||
727 | if (rename(tmp, identity_file) == -1) { | ||
728 | error("rename\"%s\" to \"%s\": %s", tmp, identity_file, | ||
729 | strerror(errno)); | ||
730 | unlink(tmp); | ||
731 | unlink(old); | ||
732 | exit(1); | ||
733 | } | ||
734 | |||
735 | fprintf(stderr, "%s updated.\n", identity_file); | ||
736 | fprintf(stderr, "Original contents retained as %s\n", old); | ||
737 | if (has_unhashed) { | ||
738 | fprintf(stderr, "WARNING: %s contains unhashed " | ||
739 | "entries\n", old); | ||
740 | fprintf(stderr, "Delete this file to ensure privacy " | ||
741 | "of hostnames\n"); | ||
742 | } | ||
743 | } | ||
744 | |||
745 | exit(0); | ||
746 | } | ||
747 | |||
543 | /* | 748 | /* |
544 | * Perform changing a passphrase. The argument is the passwd structure | 749 | * Perform changing a passphrase. The argument is the passwd structure |
545 | * for the current user. | 750 | * for the current user. |
@@ -766,6 +971,8 @@ usage(void) | |||
766 | fprintf(stderr, " -y Read private key file and print public key.\n"); | 971 | fprintf(stderr, " -y Read private key file and print public key.\n"); |
767 | fprintf(stderr, " -t type Specify type of key to create.\n"); | 972 | fprintf(stderr, " -t type Specify type of key to create.\n"); |
768 | fprintf(stderr, " -B Show bubblebabble digest of key file.\n"); | 973 | fprintf(stderr, " -B Show bubblebabble digest of key file.\n"); |
974 | fprintf(stderr, " -H Hash names in known_hosts file\n"); | ||
975 | fprintf(stderr, " -F hostname Find hostname in known hosts file\n"); | ||
769 | fprintf(stderr, " -C comment Provide new comment.\n"); | 976 | fprintf(stderr, " -C comment Provide new comment.\n"); |
770 | fprintf(stderr, " -N phrase Provide new passphrase.\n"); | 977 | fprintf(stderr, " -N phrase Provide new passphrase.\n"); |
771 | fprintf(stderr, " -P phrase Provide old passphrase.\n"); | 978 | fprintf(stderr, " -P phrase Provide old passphrase.\n"); |
@@ -789,7 +996,7 @@ main(int ac, char **av) | |||
789 | { | 996 | { |
790 | char dotsshdir[MAXPATHLEN], comment[1024], *passphrase1, *passphrase2; | 997 | char dotsshdir[MAXPATHLEN], comment[1024], *passphrase1, *passphrase2; |
791 | char out_file[MAXPATHLEN], *reader_id = NULL; | 998 | char out_file[MAXPATHLEN], *reader_id = NULL; |
792 | char *resource_record_hostname = NULL; | 999 | char *rr_hostname = NULL; |
793 | Key *private, *public; | 1000 | Key *private, *public; |
794 | struct passwd *pw; | 1001 | struct passwd *pw; |
795 | struct stat st; | 1002 | struct stat st; |
@@ -823,7 +1030,7 @@ main(int ac, char **av) | |||
823 | } | 1030 | } |
824 | 1031 | ||
825 | while ((opt = getopt(ac, av, | 1032 | while ((opt = getopt(ac, av, |
826 | "degiqpclBRvxXyb:f:t:U:D:P:N:C:r:g:T:G:M:S:a:W:")) != -1) { | 1033 | "degiqpclBHvxXyF:b:f:t:U:D:P:N:C:r:g:R:T:G:M:S:a:W:")) != -1) { |
827 | switch (opt) { | 1034 | switch (opt) { |
828 | case 'b': | 1035 | case 'b': |
829 | bits = atoi(optarg); | 1036 | bits = atoi(optarg); |
@@ -832,6 +1039,17 @@ main(int ac, char **av) | |||
832 | exit(1); | 1039 | exit(1); |
833 | } | 1040 | } |
834 | break; | 1041 | break; |
1042 | case 'F': | ||
1043 | find_host = 1; | ||
1044 | rr_hostname = optarg; | ||
1045 | break; | ||
1046 | case 'H': | ||
1047 | hash_hosts = 1; | ||
1048 | break; | ||
1049 | case 'R': | ||
1050 | delete_host = 1; | ||
1051 | rr_hostname = optarg; | ||
1052 | break; | ||
835 | case 'l': | 1053 | case 'l': |
836 | print_fingerprint = 1; | 1054 | print_fingerprint = 1; |
837 | break; | 1055 | break; |
@@ -863,10 +1081,6 @@ main(int ac, char **av) | |||
863 | case 'q': | 1081 | case 'q': |
864 | quiet = 1; | 1082 | quiet = 1; |
865 | break; | 1083 | break; |
866 | case 'R': | ||
867 | /* unused */ | ||
868 | exit(0); | ||
869 | break; | ||
870 | case 'e': | 1084 | case 'e': |
871 | case 'x': | 1085 | case 'x': |
872 | /* export key */ | 1086 | /* export key */ |
@@ -901,7 +1115,7 @@ main(int ac, char **av) | |||
901 | } | 1115 | } |
902 | break; | 1116 | break; |
903 | case 'r': | 1117 | case 'r': |
904 | resource_record_hostname = optarg; | 1118 | rr_hostname = optarg; |
905 | break; | 1119 | break; |
906 | case 'W': | 1120 | case 'W': |
907 | generator_wanted = atoi(optarg); | 1121 | generator_wanted = atoi(optarg); |
@@ -944,6 +1158,8 @@ main(int ac, char **av) | |||
944 | printf("Can only have one of -p and -c.\n"); | 1158 | printf("Can only have one of -p and -c.\n"); |
945 | usage(); | 1159 | usage(); |
946 | } | 1160 | } |
1161 | if (delete_host || hash_hosts || find_host) | ||
1162 | do_known_hosts(pw, rr_hostname); | ||
947 | if (print_fingerprint || print_bubblebabble) | 1163 | if (print_fingerprint || print_bubblebabble) |
948 | do_fingerprint(pw); | 1164 | do_fingerprint(pw); |
949 | if (change_passphrase) | 1165 | if (change_passphrase) |
@@ -956,8 +1172,8 @@ main(int ac, char **av) | |||
956 | do_convert_from_ssh2(pw); | 1172 | do_convert_from_ssh2(pw); |
957 | if (print_public) | 1173 | if (print_public) |
958 | do_print_public(pw); | 1174 | do_print_public(pw); |
959 | if (resource_record_hostname != NULL) { | 1175 | if (rr_hostname != NULL) { |
960 | do_print_resource_record(pw, resource_record_hostname); | 1176 | do_print_resource_record(pw, rr_hostname); |
961 | } | 1177 | } |
962 | if (reader_id != NULL) { | 1178 | if (reader_id != NULL) { |
963 | #ifdef SMARTCARD | 1179 | #ifdef SMARTCARD |