[openssh-commits] [openssh] 09/20: upstream commit

git+noreply at mindrot.org git+noreply at mindrot.org
Tue Jan 20 00:27:53 EST 2015


This is an automated email from the git hooks/post-receive script.

djm pushed a commit to branch master
in repository openssh.

commit cecb30bc2ba6d594366e657d664d5c494b6c8a7f
Author: djm at openbsd.org <djm at openbsd.org>
Date:   Sun Jan 18 21:49:42 2015 +0000

    upstream commit
    
    make ssh-keygen use hostkeys_foreach(). Removes some
     horrendous code; ok markus@
---
 ssh-keygen.c | 324 ++++++++++++++++++++++-------------------------------------
 1 file changed, 120 insertions(+), 204 deletions(-)

diff --git a/ssh-keygen.c b/ssh-keygen.c
index 500a366..02db8b2 100644
--- a/ssh-keygen.c
+++ b/ssh-keygen.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-keygen.c,v 1.255 2015/01/18 13:22:28 djm Exp $ */
+/* $OpenBSD: ssh-keygen.c,v 1.256 2015/01/18 21:49:42 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo at cs.hut.fi>
  * Copyright (c) 1994 Tatu Ylonen <ylo at cs.hut.fi>, Espoo, Finland
@@ -1031,50 +1031,110 @@ do_gen_all_hostkeys(struct passwd *pw)
 		printf("\n");
 }
 
-static void
-printhost(FILE *f, const char *name, struct sshkey *public,
-    int ca, int revoked, int hash)
+struct known_hosts_ctx {
+	FILE *out;
+	const char *host;
+	int has_unhashed, found_key, inplace, invalid;
+};
+
+static int
+known_hosts_hash(struct hostkey_foreach_line *l, void *_ctx)
 {
-	if (print_fingerprint) {
-		enum sshkey_fp_rep rep;
-		int fptype;
-		char *fp, *ra;
+	struct known_hosts_ctx *ctx = (struct known_hosts_ctx *)_ctx;
+	char *hashed, *cp, *hosts, *ohosts;
+	int has_wild = l->hosts && strcspn(l->hosts, "*?!") != strlen(l->hosts);
 
-		fptype = print_bubblebabble ?
-		    SSH_DIGEST_SHA1 : fingerprint_hash;
-		rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_DEFAULT;
-		fp = sshkey_fingerprint(public, fptype, rep);
-		ra = sshkey_fingerprint(public, fingerprint_hash,
-		    SSH_FP_RANDOMART);
-		printf("%u %s %s (%s)\n", sshkey_size(public), fp, name,
-		    sshkey_type(public));
-		if (log_level >= SYSLOG_LEVEL_VERBOSE)
-			printf("%s\n", ra);
-		free(ra);
-		free(fp);
-	} else {
-		int r;
+	/* Retain invalid lines when hashing, but mark file as invalid. */
+	if (l->status == HKF_STATUS_INVALID) {
+		ctx->invalid = 1;
+		fprintf(stderr, "%s:%ld: invalid line\n", l->path, l->linenum);
+		fprintf(ctx->out, "%s\n", l->line);
+		return 0;
+	}
 
-		if (hash && (name = host_hash(name, NULL, 0)) == NULL)
+	/*
+	 * Don't hash hosts already already hashed, with wildcard characters
+	 * or a CA/revocation marker.
+	 */
+	if (l->was_hashed || has_wild || l->marker != MRK_NONE) {
+		fprintf(ctx->out, "%s\n", l->line);
+		if (has_wild && !find_host) {
+			fprintf(stderr, "%s:%ld: ignoring host name "
+			    "with wildcard: %.64s\n", l->path,
+			    l->linenum, l->hosts);
+			ctx->has_unhashed = 1;
+		}
+		return 0;
+	}
+	/*
+	 * Split any comma-separated hostnames from the host list,
+	 * hash and store separately.
+	 */
+	ohosts = hosts = xstrdup(l->hosts);
+	while ((cp = strsep(&hosts, ",")) != NULL && *cp != '\0') {
+		if ((hashed = host_hash(cp, NULL, 0)) == NULL)
 			fatal("hash_host failed");
-		fprintf(f, "%s%s%s ", ca ? CA_MARKER " " : "",
-		    revoked ? REVOKE_MARKER " " : "" , name);
-		if ((r = sshkey_write(public, f)) != 0)
-			fatal("key_write failed: %s", ssh_err(r));
-		fprintf(f, "\n");
+		fprintf(ctx->out, "%s %s\n", hashed, l->rawkey);
+		ctx->has_unhashed = 1;
 	}
+	free(ohosts);
+	return 0;
+}
+
+static int
+known_hosts_find_delete(struct hostkey_foreach_line *l, void *_ctx)
+{
+	struct known_hosts_ctx *ctx = (struct known_hosts_ctx *)_ctx;
+
+	if (l->status == HKF_STATUS_HOST_MATCHED) {
+		if (delete_host) {
+			if (l->marker != MRK_NONE) {
+				/* Don't remove CA and revocation lines */
+				fprintf(ctx->out, "%s\n", l->line);
+			} else {
+				/*
+				 * Hostname matches and has no CA/revoke
+				 * marker, delete it by *not* writing the
+				 * line to ctx->out.
+				 */
+				ctx->found_key = 1;
+				if (!quiet)
+					printf("# Host %s found: line %ld\n",
+					    ctx->host, l->linenum);
+			}
+			return 0;
+		} else if (find_host) {
+			ctx->found_key = 1;
+			if (!quiet) {
+				printf("# Host %s found: line %ld %s\n",
+				    ctx->host,
+				    l->linenum, l->marker == MRK_CA ? "CA" :
+				    (l->marker == MRK_REVOKE ? "REVOKED" : ""));
+			}
+			if (hash_hosts)
+				known_hosts_hash(l, ctx);
+			else
+				fprintf(ctx->out, "%s\n", l->line);
+			return 0;
+		}
+	} else if (delete_host) {
+		/* Retain non-matching hosts when deleting */
+		if (l->status == HKF_STATUS_INVALID) {
+			ctx->invalid = 1;
+			fprintf(stderr, "%s:%ld: invalid line\n",
+			    l->path, l->linenum);
+		}
+		fprintf(ctx->out, "%s\n", l->line);
+	}
+	return 0;
 }
 
 static void
 do_known_hosts(struct passwd *pw, const char *name)
 {
-	FILE *in, *out = stdout;
-	struct sshkey *pub;
-	char *cp, *cp2, *kp, *kp2;
-	char line[16*1024], tmp[PATH_MAX], old[PATH_MAX];
-	int c, skip = 0, inplace = 0, num = 0, invalid = 0, has_unhashed = 0;
-	int r, ca, revoked;
-	int found_key = 0;
+	char *cp, tmp[MAXPATHLEN], old[MAXPATHLEN];
+	int r, fd, oerrno;
+	struct known_hosts_ctx ctx;
 
 	if (!have_identity) {
 		cp = tilde_expand_filename(_PATH_SSH_USER_HOSTFILE, pw->pw_uid);
@@ -1084,10 +1144,11 @@ do_known_hosts(struct passwd *pw, const char *name)
 		free(cp);
 		have_identity = 1;
 	}
-	if ((in = fopen(identity_file, "r")) == NULL)
-		fatal("%s: %s: %s", __progname, identity_file, strerror(errno));
 
-	/* XXX this code is a mess; refactor -djm */
+	memset(&ctx, 0, sizeof(ctx));
+	ctx.out = stdout;
+	ctx.host = name;
+
 	/*
 	 * Find hosts goes to stdout, hash and deletions happen in-place
 	 * A corner case is ssh-keygen -HF foo, which should go to stdout
@@ -1099,184 +1160,39 @@ do_known_hosts(struct passwd *pw, const char *name)
 		    strlcat(old, ".old", sizeof(old)) >= sizeof(old))
 			fatal("known_hosts path too long");
 		umask(077);
-		if ((c = mkstemp(tmp)) == -1)
+		if ((fd = mkstemp(tmp)) == -1)
 			fatal("mkstemp: %s", strerror(errno));
-		if ((out = fdopen(c, "w")) == NULL) {
-			c = errno;
+		if ((ctx.out = fdopen(fd, "w")) == NULL) {
+			oerrno = errno;
 			unlink(tmp);
-			fatal("fdopen: %s", strerror(c));
+			fatal("fdopen: %s", strerror(oerrno));
 		}
-		inplace = 1;
+		ctx.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;
-		}
-		/* Check whether this is a CA key or revocation marker */
-		if (strncasecmp(cp, CA_MARKER, sizeof(CA_MARKER) - 1) == 0 &&
-		    (cp[sizeof(CA_MARKER) - 1] == ' ' ||
-		    cp[sizeof(CA_MARKER) - 1] == '\t')) {
-			ca = 1;
-			cp += sizeof(CA_MARKER);
-		} else
-			ca = 0;
-		if (strncasecmp(cp, REVOKE_MARKER,
-		    sizeof(REVOKE_MARKER) - 1) == 0 &&
-		    (cp[sizeof(REVOKE_MARKER) - 1] == ' ' ||
-		    cp[sizeof(REVOKE_MARKER) - 1] == '\t')) {
-			revoked = 1;
-			cp += sizeof(REVOKE_MARKER);
-		} else
-			revoked = 0;
-
-		/* Find the end of the host name portion. */
-		for (kp = cp; *kp && *kp != ' ' && *kp != '\t'; kp++)
-			;
+	/* XXX support identity_file == "-" for stdin */
+	if ((r = hostkeys_foreach(identity_file,
+	    hash_hosts ? known_hosts_hash : known_hosts_find_delete, &ctx,
+	    name, find_host ? HKF_WANT_MATCH_HOST : 0)) != 0)
+		fatal("%s: hostkeys_foreach failed: %s", __func__, ssh_err(r));
 
-		if (*kp == '\0' || *(kp + 1) == '\0') {
-			error("line %d missing key: %.40s...",
-			    num, line);
-			invalid = 1;
-			continue;
-		}
-		*kp++ = '\0';
-		kp2 = kp;
-
-		if ((pub = sshkey_new(KEY_RSA1)) == NULL)
-			fatal("sshkey_new failed");
-		if ((r = sshkey_read(pub, &kp)) != 0) {
-			kp = kp2;
-			sshkey_free(pub);
-			if ((pub = sshkey_new(KEY_UNSPEC)) == NULL)
-				fatal("sshkey_new failed");
-			if ((r = sshkey_read(pub, &kp)) != 0) {
-				error("line %d invalid key: %.40s...",
-				    num, line);
-				sshkey_free(pub);
-				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) {
-					if (!quiet)
-						printf("# Host %s found: "
-						    "line %d type %s%s\n", name,
-						    num, sshkey_type(pub),
-						    ca ? " (CA key)" :
-						    revoked? " (revoked)" : "");
-					printhost(out, cp, pub, ca, revoked, 0);
-					found_key = 1;
-				}
-				if (delete_host) {
-					if (!c || ca || revoked) {
-						printhost(out, cp, pub,
-						    ca, revoked, 0);
-					} else {
-						printf("# Host %s found: "
-						    "line %d type %s\n", name,
-						    num, sshkey_type(pub));
-					}
-				}
-			} else if (hash_hosts)
-				printhost(out, cp, pub, ca, revoked, 0);
-		} else {
-			if (find_host || delete_host) {
-				c = (match_hostname(name, cp,
-				    strlen(cp)) == 1);
-				if (find_host && c) {
-					if (!quiet)
-						printf("# Host %s found: "
-						    "line %d type %s%s\n", name,
-						    num, sshkey_type(pub),
-						    ca ? " (CA key)" : "");
-					printhost(out, name, pub, ca, revoked,
-					    hash_hosts && !(ca || revoked));
-					found_key = 1;
-				}
-				if (delete_host) {
-					if (!c || ca || revoked) {
-						printhost(out, cp, pub,
-						    ca, revoked, 0);
-					} else {
-						printf("# Host %s found: "
-						    "line %d type %s\n", name,
-						    num, sshkey_type(pub));
-					}
-				}
-			} else if (hash_hosts && (ca || revoked)) {
-				/* Don't hash CA and revoked keys' hostnames */
-				printhost(out, cp, pub, ca, revoked, 0);
-				has_unhashed = 1;
-			} else if (hash_hosts) {
-				/* Hash each hostname separately */
-				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);
-						printhost(out, cp2, pub, ca,
-						    revoked, 0);
-						has_unhashed = 1;
-					} else {
-						printhost(out, cp2, pub, ca,
-						    revoked, 1);
-					}
-				}
-			}
-		}
-		sshkey_free(pub);
-	}
-	fclose(in);
+	if (ctx.inplace)
+		fclose(ctx.out);
 
-	if (invalid) {
+	if (ctx.invalid) {
 		fprintf(stderr, "%s is not a valid known_hosts file.\n",
 		    identity_file);
-		if (inplace) {
+		if (ctx.inplace) {
 			fprintf(stderr, "Not replacing existing known_hosts "
 			    "file because of errors\n");
-			fclose(out);
 			unlink(tmp);
 		}
 		exit(1);
-	}
-
-	if (inplace) {
-		fclose(out);
-
+	} else if (delete_host && !ctx.found_key) {
+		fprintf(stderr, "Host %s not found in %s\n",
+		    name, identity_file);
+		unlink(tmp);
+	} else if (ctx.inplace) {
 		/* Backup existing file */
 		if (unlink(old) == -1 && errno != ENOENT)
 			fatal("unlink %.100s: %s", old, strerror(errno));
@@ -1294,7 +1210,7 @@ do_known_hosts(struct passwd *pw, const char *name)
 
 		fprintf(stderr, "%s updated.\n", identity_file);
 		fprintf(stderr, "Original contents retained as %s\n", old);
-		if (has_unhashed) {
+		if (ctx.has_unhashed) {
 			fprintf(stderr, "WARNING: %s contains unhashed "
 			    "entries\n", old);
 			fprintf(stderr, "Delete this file to ensure privacy "
@@ -1302,7 +1218,7 @@ do_known_hosts(struct passwd *pw, const char *name)
 		}
 	}
 
-	exit (find_host && !found_key);
+	exit (find_host && !ctx.found_key);
 }
 
 /*

-- 
To stop receiving notification emails like this one, please contact
djm at mindrot.org.


More information about the openssh-commits mailing list