[openssh-commits] [openssh] 01/04: upstream: Add a "ssh -Z user at host" mode that dumps the pubkeys that

git+noreply at mindrot.org git+noreply at mindrot.org
Mon Aug 3 16:54:23 AEST 2026


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

djm pushed a commit to branch master
in repository openssh.

commit 29f1b46e0f6fb4aba9ae34e4b46532b5748f395e
Author: djm at openbsd.org <djm at openbsd.org>
AuthorDate: Mon Aug 3 06:47:24 2026 +0000

    upstream: Add a "ssh -Z user at host" mode that dumps the pubkeys that
    
    will be tried for authentication in the order that they will be used.
    
    feedback tb@ ok dtucker@
    
    OpenBSD-Commit-ID: 617a7f149d1410980eac551e4780280190a5f218
---
 ssh.1         | 10 +++++---
 ssh.c         | 73 +++++++++++++++++++++++++++++++++--------------------------
 sshconnect.h  |  4 +++-
 sshconnect2.c | 38 +++++++++++++++++++++++++------
 4 files changed, 82 insertions(+), 43 deletions(-)

diff --git a/ssh.1 b/ssh.1
index 747a126a1..ba24650e8 100644
--- a/ssh.1
+++ b/ssh.1
@@ -33,8 +33,8 @@
 .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.\" $OpenBSD: ssh.1,v 1.452 2026/07/11 11:15:03 naddy Exp $
-.Dd $Mdocdate: July 11 2026 $
+.\" $OpenBSD: ssh.1,v 1.453 2026/08/03 06:47:24 djm Exp $
+.Dd $Mdocdate: August 3 2026 $
 .Dt SSH 1
 .Os
 .Sh NAME
@@ -42,7 +42,7 @@
 .Nd OpenSSH remote login client
 .Sh SYNOPSIS
 .Nm ssh
-.Op Fl 46AaCfGgKkMNnqsTtVvXxYy
+.Op Fl 46AaCfGgKkMNnqsTtVvZXxYy
 .Op Fl B Ar bind_interface
 .Op Fl b Ar bind_address
 .Op Fl c Ar cipher_spec
@@ -781,6 +781,10 @@ Send log information using the
 .Xr syslog 3
 system module.
 By default this information is sent to stderr.
+.Pp
+.It Fl Z
+Dump the public keys that would be attempted for authentication to the specified
+destination in preferred order and exit.
 .El
 .Pp
 .Nm
diff --git a/ssh.c b/ssh.c
index 7c644c23c..a4ebd11a4 100644
--- a/ssh.c
+++ b/ssh.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh.c,v 1.634 2026/07/06 07:49:58 djm Exp $ */
+/* $OpenBSD: ssh.c,v 1.635 2026/08/03 06:47:24 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo at cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo at cs.hut.fi>, Espoo, Finland
@@ -168,7 +168,7 @@ static void
 usage(void)
 {
 	fprintf(stderr,
-"usage: ssh [-46AaCfGgKkMNnqsTtVvXxYy] [-B bind_interface] [-b bind_address]\n"
+"usage: ssh [-46AaCfGgKkMNnqsTtVvZXxYyZ] [-B bind_interface] [-b bind_address]\n"
 "           [-c cipher_spec] [-D [bind_address:]port] [-E log_file]\n"
 "           [-e escape_char] [-F configfile] [-I pkcs11] [-i identity_file]\n"
 "           [-J destination] [-L address] [-l login_name] [-m mac_spec]\n"
@@ -621,7 +621,7 @@ main(int ac, char **av)
 {
 	struct ssh *ssh = NULL;
 	int i, r, opt, exit_status, use_syslog, direct, timeout_ms;
-	int was_addr, config_test = 0, opt_terminated = 0, want_final_pass = 0;
+	int was_addr, config_test = 0, dump_pubkeys = 0, opt_terminated = 0, want_final_pass = 0;
 	int user_on_commandline = 0, user_was_default = 0, user_expanded = 0;
 	char *p, *cp, *line, *argv0, *logfile, *args;
 	char cname[NI_MAXHOST], thishost[NI_MAXHOST];
@@ -700,8 +700,9 @@ main(int ac, char **av)
 	argv0 = av[0];
 
  again:
-	while ((opt = getopt(ac, av, "1246ab:c:e:fgi:kl:m:no:p:qstvx"
-	    "AB:CD:E:F:GI:J:KL:MNO:P:Q:R:S:TVw:W:XYy")) != -1) { /* HUZdhjruz */
+	/* remaining: HUdhjruz */
+	while ((opt = getopt(ac, av, "1246ACGKMNTVXYZafgknqstvxy"
+	    "B:D:E:F:I:J:L:O:P:Q:R:S:W:b:c:e:i:l:m:o:p:w:")) != -1) {
 		switch (opt) {
 		case '1':
 			fatal("SSH protocol v.1 is no longer supported");
@@ -741,6 +742,9 @@ main(int ac, char **av)
 			options.forward_x11 = 1;
 			options.forward_x11_trusted = 1;
 			break;
+		case 'Z':
+			dump_pubkeys = 1;
+			break;
 		case 'g':
 			options.fwd_opts.gateway_ports = 1;
 			break;
@@ -1638,6 +1642,38 @@ main(int ac, char **av)
 		}
 	}
 
+	/* load options.identity_files */
+	load_public_identity_files(cinfo);
+
+	/* optionally set the SSH_AUTHSOCKET_ENV_NAME variable */
+	if (options.identity_agent &&
+	    strcmp(options.identity_agent, SSH_AUTHSOCKET_ENV_NAME) != 0) {
+		if (strcmp(options.identity_agent, "none") == 0) {
+			unsetenv(SSH_AUTHSOCKET_ENV_NAME);
+		} else {
+			cp = options.identity_agent;
+			/* legacy (limited) format */
+			if (cp[0] == '$' && cp[1] != '{') {
+				if (!valid_env_name(cp + 1)) {
+					fatal("Invalid IdentityAgent "
+					    "environment variable name %s", cp);
+				}
+				if ((p = getenv(cp + 1)) == NULL)
+					unsetenv(SSH_AUTHSOCKET_ENV_NAME);
+				else
+					setenv(SSH_AUTHSOCKET_ENV_NAME, p, 1);
+			} else {
+				/* identity_agent specifies a path directly */
+				setenv(SSH_AUTHSOCKET_ENV_NAME, cp, 1);
+			}
+		}
+	}
+
+	if (dump_pubkeys) {
+		pubkey_dump(ssh);
+		exit(0);
+	}
+
 	/*
 	 * If hostname canonicalisation was not enabled, then we may not
 	 * have yet resolved the hostname. Do so now.
@@ -1732,33 +1768,6 @@ main(int ac, char **av)
 		}
 	}
 
-	/* load options.identity_files */
-	load_public_identity_files(cinfo);
-
-	/* optionally set the SSH_AUTHSOCKET_ENV_NAME variable */
-	if (options.identity_agent &&
-	    strcmp(options.identity_agent, SSH_AUTHSOCKET_ENV_NAME) != 0) {
-		if (strcmp(options.identity_agent, "none") == 0) {
-			unsetenv(SSH_AUTHSOCKET_ENV_NAME);
-		} else {
-			cp = options.identity_agent;
-			/* legacy (limited) format */
-			if (cp[0] == '$' && cp[1] != '{') {
-				if (!valid_env_name(cp + 1)) {
-					fatal("Invalid IdentityAgent "
-					    "environment variable name %s", cp);
-				}
-				if ((p = getenv(cp + 1)) == NULL)
-					unsetenv(SSH_AUTHSOCKET_ENV_NAME);
-				else
-					setenv(SSH_AUTHSOCKET_ENV_NAME, p, 1);
-			} else {
-				/* identity_agent specifies a path directly */
-				setenv(SSH_AUTHSOCKET_ENV_NAME, cp, 1);
-			}
-		}
-	}
-
 	if (options.forward_agent && options.forward_agent_sock_path != NULL) {
 		cp = options.forward_agent_sock_path;
 		if (cp[0] == '$') {
diff --git a/sshconnect.h b/sshconnect.h
index 2ac2c07e0..aad13c20c 100644
--- a/sshconnect.h
+++ b/sshconnect.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshconnect.h,v 1.51 2026/07/06 07:49:58 djm Exp $ */
+/* $OpenBSD: sshconnect.h,v 1.52 2026/08/03 06:47:24 djm Exp $ */
 
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
@@ -91,6 +91,8 @@ void	 ssh_kex2(struct ssh *ssh, char *, struct sockaddr_storage *, u_short,
 void	 ssh_userauth2(struct ssh *ssh, const char *, const char *,
     char *, Sensitive *);
 
+void	 pubkey_dump(struct ssh *);
+
 int	 ssh_local_cmd(const char *);
 
 void	 maybe_add_key_to_agent(const char *, struct sshkey *,
diff --git a/sshconnect2.c b/sshconnect2.c
index 3ff05a578..b2eb17bd4 100644
--- a/sshconnect2.c
+++ b/sshconnect2.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshconnect2.c,v 1.390 2026/07/27 12:28:52 markus Exp $ */
+/* $OpenBSD: sshconnect2.c,v 1.391 2026/08/03 06:47:24 djm Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  * Copyright (c) 2008 Damien Miller.  All rights reserved.
@@ -1648,11 +1648,13 @@ get_agent_identities(struct ssh *ssh, int *agent_fdp,
 			debug_fr(r, "ssh_get_authentication_socket");
 		return r;
 	}
-	if ((r = ssh_agent_bind_hostkey(agent_fd, ssh->kex->initial_hostkey,
-	    ssh->kex->session_id, ssh->kex->initial_sig, 0)) == 0)
-		debug_f("bound agent to hostkey");
-	else
-		debug2_fr(r, "ssh_agent_bind_hostkey");
+	if (ssh != NULL && ssh->kex != NULL) {
+		if ((r = ssh_agent_bind_hostkey(agent_fd, ssh->kex->initial_hostkey,
+		    ssh->kex->session_id, ssh->kex->initial_sig, 0)) == 0)
+			debug_f("bound agent to hostkey");
+		else
+			debug2_fr(r, "ssh_agent_bind_hostkey");
+	}
 
 	if ((r = ssh_fetch_identitylist(agent_fd, &idlist)) != 0) {
 		debug_fr(r, "ssh_fetch_identitylist");
@@ -1810,7 +1812,8 @@ pubkey_prepare(struct ssh *ssh, Authctxt *authctxt)
 			    "not in PubkeyAcceptedAlgorithms",
 			    sshkey_ssh_name(id->key), id->filename);
 			disallowed = 1;
-		} else if (ssh->kex->server_sig_algs != NULL &&
+		} else if (ssh != NULL && ssh->kex != NULL &&
+		    ssh->kex->server_sig_algs != NULL &&
 		    (cp = key_sig_algorithm(ssh, id->key)) == NULL) {
 			debug("Skipping %s key %s - corresponding algorithm "
 			    "not supported by server",
@@ -1854,6 +1857,27 @@ pubkey_cleanup(struct ssh *ssh)
 	}
 }
 
+void
+pubkey_dump(struct ssh *ssh)
+{
+	Authctxt authctxt;
+	Identity *id;
+	char *ident;
+
+	memset(&authctxt, 0, sizeof(authctxt));
+	authctxt.agent_fd = -1;
+	ssh->authctxt = &authctxt;
+
+	pubkey_prepare(ssh, &authctxt);
+	TAILQ_FOREACH(id, &authctxt.keys, next) {
+		ident = format_identity(id);
+		fprintf(stdout, "%s\n", ident);
+		free(ident);
+	}
+	pubkey_cleanup(ssh);
+	ssh->authctxt = NULL;
+}
+
 static void
 pubkey_reset(Authctxt *authctxt)
 {

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


More information about the openssh-commits mailing list