-static void
-print_host(FILE *f, const char *name, Key *public, int hash)
-{
- if (print_fingerprint) {
- enum fp_rep rep;
- enum fp_type fptype;
- char *fp, *ra;
-
- fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5;
- rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX;
- fp = key_fingerprint(public, fptype, rep);
- ra = key_fingerprint(public, fptype, SSH_FP_RANDOMART);
- printf("%u %s %s (%s)\n", key_size(public), fp, name,
- key_type(public));
- if (log_level >= SYSLOG_LEVEL_VERBOSE)
- printf("%s\n", ra);
- xfree(ra);
- xfree(fp);
- } else {
- if (hash && (name = host_hash(name, NULL, 0)) == NULL)
- fatal("hash_host failed");
- fprintf(f, "%s ", name);
- if (!key_write(public, f))
- fatal("key_write failed");
- fprintf(f, "\n");
- }
-}
-
-static void
-do_known_hosts(struct passwd *pw, const char *name)
-{
- FILE *in, *out = stdout;
- Key *public;
- char *cp, *cp2, *kp, *kp2;
- char line[16*1024], tmp[MAXPATHLEN], old[MAXPATHLEN];
- int c, skip = 0, inplace = 0, num = 0, invalid = 0, has_unhashed = 0;
-
- if (!have_identity) {
- cp = tilde_expand_filename(_PATH_SSH_USER_HOSTFILE, pw->pw_uid);
- if (strlcpy(identity_file, cp, sizeof(identity_file)) >=
- sizeof(identity_file))
- fatal("Specified known hosts path too long");
- xfree(cp);
- have_identity = 1;
- }
- if ((in = fopen(identity_file, "r")) == NULL)
- fatal("fopen: %s", strerror(errno));
-
- /*
- * Find hosts goes to stdout, hash and deletions happen in-place
- * A corner case is ssh-keygen -HF foo, which should go to stdout
- */
- if (!find_host && (hash_hosts || delete_host)) {
- if (strlcpy(tmp, identity_file, sizeof(tmp)) >= sizeof(tmp) ||
- strlcat(tmp, ".XXXXXXXXXX", sizeof(tmp)) >= sizeof(tmp) ||
- strlcpy(old, identity_file, sizeof(old)) >= sizeof(old) ||
- strlcat(old, ".old", sizeof(old)) >= sizeof(old))
- fatal("known_hosts path too long");
- umask(077);
- if ((c = mkstemp(tmp)) == -1)
- fatal("mkstemp: %s", strerror(errno));
- if ((out = fdopen(c, "w")) == NULL) {
- c = errno;
- unlink(tmp);
- fatal("fdopen: %s", strerror(c));
- }
- inplace = 1;
- }
-
- while (fgets(line, sizeof(line), in)) {
- if ((cp = strchr(line, '\n')) == NULL) {
- error("line %d too long: %.40s...", num + 1, line);
- skip = 1;
- invalid = 1;
- continue;
- }
- num++;
- if (skip) {
- skip = 0;
- continue;
- }
- *cp = '\0';
-
- /* Skip leading whitespace, empty and comment lines. */
- for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
- ;
- if (!*cp || *cp == '\n' || *cp == '#') {
- if (inplace)
- fprintf(out, "%s\n", cp);
- continue;
- }
- /* Find the end of the host name portion. */
- for (kp = cp; *kp && *kp != ' ' && *kp != '\t'; kp++)
- ;
- if (*kp == '\0' || *(kp + 1) == '\0') {
- error("line %d missing key: %.40s...",
- num, line);
- invalid = 1;
- continue;
- }
- *kp++ = '\0';
- kp2 = kp;
-
- public = key_new(KEY_RSA1);
- if (key_read(public, &kp) != 1) {
- kp = kp2;
- key_free(public);
- public = key_new(KEY_UNSPEC);
- if (key_read(public, &kp) != 1) {
- error("line %d invalid key: %.40s...",
- num, line);
- key_free(public);
- invalid = 1;
- continue;
- }
- }
-
- if (*cp == HASH_DELIM) {
- if (find_host || delete_host) {
- cp2 = host_hash(name, cp, strlen(cp));
- if (cp2 == NULL) {
- error("line %d: invalid hashed "
- "name: %.64s...", num, line);
- invalid = 1;
- continue;
- }
- c = (strcmp(cp2, cp) == 0);
- if (find_host && c) {
- printf("# Host %s found: "
- "line %d type %s\n", name,
- num, key_type(public));
- print_host(out, cp, public, 0);
- }
- if (delete_host && !c)
- print_host(out, cp, public, 0);
- } else if (hash_hosts)
- print_host(out, cp, public, 0);
- } else {
- if (find_host || delete_host) {
- c = (match_hostname(name, cp,
- strlen(cp)) == 1);
- if (find_host && c) {
- printf("# Host %s found: "
- "line %d type %s\n", name,
- num, key_type(public));
- print_host(out, name, public,
- hash_hosts);
- }
- if (delete_host && !c)
- print_host(out, cp, public, 0);
- } else if (hash_hosts) {
- for (cp2 = strsep(&cp, ",");
- cp2 != NULL && *cp2 != '\0';
- cp2 = strsep(&cp, ",")) {
- if (strcspn(cp2, "*?!") != strlen(cp2))
- fprintf(stderr, "Warning: "
- "ignoring host name with "
- "metacharacters: %.64s\n",
- cp2);
- else
- print_host(out, cp2, public, 1);
- }
- has_unhashed = 1;
- }
- }
- key_free(public);
- }
- fclose(in);
-
- if (invalid) {
- fprintf(stderr, "%s is not a valid known_hosts file.\n",
- identity_file);
- if (inplace) {
- fprintf(stderr, "Not replacing existing known_hosts "
- "file because of errors\n");
- fclose(out);
- unlink(tmp);
- }
- exit(1);
- }
-
- if (inplace) {
- fclose(out);
-
- /* Backup existing file */
- if (unlink(old) == -1 && errno != ENOENT)
- fatal("unlink %.100s: %s", old, strerror(errno));
- if (link(identity_file, old) == -1)
- fatal("link %.100s to %.100s: %s", identity_file, old,
- strerror(errno));
- /* Move new one into place */
- if (rename(tmp, identity_file) == -1) {
- error("rename\"%s\" to \"%s\": %s", tmp, identity_file,
- strerror(errno));
- unlink(tmp);
- unlink(old);
- exit(1);
- }
-
- fprintf(stderr, "%s updated.\n", identity_file);
- fprintf(stderr, "Original contents retained as %s\n", old);
- if (has_unhashed) {
- fprintf(stderr, "WARNING: %s contains unhashed "
- "entries\n", old);
- fprintf(stderr, "Delete this file to ensure privacy "
- "of hostnames\n");
- }
- }
-
- exit(0);
-}
-