public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
From: Mattias Ellert <mattias.ellert@physics.uu.se>
To: git-commits@fedoraproject.org
Subject: [rpms/gsi-openssh] epel10: Based on openssh-9.9p1-32.el10
Date: Tue, 22 Sep 2026 19:59:47 GMT	[thread overview]
Message-ID: <179010718716.1.8971071598837401023.rpms-gsi-openssh-c69d9b538f65@fedoraproject.org> (raw)

A new commit has been pushed.

Repo   : rpms/gsi-openssh
Branch : epel10
Commit : c69d9b538f65110ba2f26df5e186fa7e933f922e
Author : Mattias Ellert <mattias.ellert@physics.uu.se>
Date   : 2026-09-22T20:25:39+02:00
Stats  : +770/-179 in 14 file(s)
URL    : https://src.fedoraproject.org/rpms/gsi-openssh/c/c69d9b538f65110ba2f26df5e186fa7e933f922e?branch=epel10

Log:
Based on openssh-9.9p1-32.el10

---
diff --git a/gsi-openssh.spec b/gsi-openssh.spec
index b80cf40..52533d4 100644
--- a/gsi-openssh.spec
+++ b/gsi-openssh.spec
@@ -28,7 +28,7 @@
 Summary: An implementation of the SSH protocol with GSI authentication
 Name: gsi-openssh
 Version: %{openssh_ver}
-Release: 6%{?dist}
+Release: 7%{?dist}
 Provides: gsissh = %{version}-%{release}
 Obsoletes: gsissh < 5.8p2-2
 URL: http://www.openssh.com/portable.html
@@ -231,6 +231,26 @@ Patch1043: openssh-9.9p1-authorized-keys-principles-option.patch
 # upstream 607bd871ec029e9aa22e632a22547250f3cae223
 # upstream 1340d3fa8e4bb122906a82159c4c9b91584d65ce
 Patch1044: openssh-9.9p1-proxyjump-username-validity-checks.patch
+# upstream 36480181fa22f98e180b4f9e10203480c0346c78
+Patch1045: openssh-9.9p1-scp-remote-glob.patch
+# upstream e8bdfb151a356d0171fea4194dd205fbb252be23
+Patch1046: openssh-9.9p1-cve-2026-60002.patch
+# upstream 8b05bbeb293c5f777915e37e9ed43a06fb8e7614
+# upstream 5a5e47740b6466d58242aca28b9e584bab4ccf1d
+Patch1047: openssh-9.9p1-copy-data-ext-self-copy.patch
+# upstream 6a57081dc35acf3ee298108d4bc3580489608d5f
+Patch1048: openssh-10.4p1-CVE-2026-59995.patch
+# upstream 8dfe7ed6e2fd988de08df508355a196b956b2753
+# upstream d322f2ccf7da095ce94d1d99cb563246f61487b0
+# combines CVE-2026-59999 and CVE-2026-73283
+# downstream specific fix, drop on rebase
+Patch1049: openssh-10.4p1-CVE-2026-59999.patch
+# upstream 6a57081dc35acf3ee298108d4bc3580489608d5f
+Patch1050: openssh-10.5p1-CVE-2026-73281.patch
+# upstream 9910d5ef53124ce1157d57bc11e222658aa41299
+Patch1051: openssh-10.5p1-CVE-2026-73282.patch
+# upstream d43ba60c91cb323ca921049b7d43b1908c318454
+Patch1052: openssh-9.9p1-CVE-2026-60001.patch
 
 # This is the patch that adds GSI support
 # Based on hpn_isshd-gsi.7.5p1b.patch from Globus upstream
@@ -425,6 +445,14 @@ gpgv2 --quiet --keyring %{SOURCE3} %{SOURCE1} %{SOURCE0}
 %patch -P 1042 -p1 -b .ecdsa-incomplete-application
 %patch -P 1043 -p1 -b .authorized-keys-principles-option
 %patch -P 1044 -p1 -b .proxyjump-username-validity-checks
+%patch -P 1045 -p1 -b .scp-remote-glob
+%patch -P 1046 -p1 -b .cve-2026-60002
+%patch -P 1047 -p1 -b .copy-data-ext-self-copy
+%patch -P 1048 -p1 -b .CVE-2026-59995
+%patch -P 1049 -p1 -b .CVE-2026-59999
+%patch -P 1050 -p1 -b .CVE-2026-73281
+%patch -P 1051 -p1 -b .CVE-2026-73282
+%patch -P 1052 -p1 -b .CVE-2026-60001
 
 %patch -P 100 -p1 -b .coverity
 
@@ -650,6 +678,9 @@ fi
 %ghost %attr(0644,root,root) %{_localstatedir}/lib/.gsissh-host-keys-migration
 
 %changelog
+* Tue Sep 22 2026 Mattias Ellert <mattias.ellert@physics.uu.se> - 9.9p1-7
+- Based on openssh-9.9p1-32.el10
+
 * Fri May 29 2026 Mattias Ellert <mattias.ellert@physics.uu.se> - 9.9p1-6
 - Based on openssh-9.9p1-26.el10
 

diff --git a/openssh-10.4p1-CVE-2026-59995.patch b/openssh-10.4p1-CVE-2026-59995.patch
new file mode 100644
index 0000000..0ba8388
--- /dev/null
+++ b/openssh-10.4p1-CVE-2026-59995.patch
@@ -0,0 +1,20 @@
+diff --git a/sftp.c b/sftp.c
+index 0ab9206c2..0b57e0833 100644
+--- a/sftp.c
++++ b/sftp.c
+@@ -2289,13 +2289,8 @@ interactive_loop(struct sftp_conn *conn, char *file1, char *file2)
+ 				return (-1);
+ 			}
+ 		} else {
+-			/* XXX this is wrong wrt quoting */
+-			snprintf(cmd, sizeof cmd, "get%s %s%s%s",
+-			    global_aflag ? " -a" : "", dir,
+-			    file2 == NULL ? "" : " ",
+-			    file2 == NULL ? "" : file2);
+-			err = parse_dispatch_command(conn, cmd,
+-			    &remote_path, startdir, 1, 0);
++			err = process_get(conn, dir, file2, remote_path, 0, 0,
++			    global_aflag, 0);
+ 			free(dir);
+ 			free(startdir);
+ 			free(remote_path);

diff --git a/openssh-10.4p1-CVE-2026-59999.patch b/openssh-10.4p1-CVE-2026-59999.patch
new file mode 100644
index 0000000..b1bf58c
--- /dev/null
+++ b/openssh-10.4p1-CVE-2026-59999.patch
@@ -0,0 +1,78 @@
+diff --git a/auth-options.c b/auth-options.c
+index e15f600ab..c5fc4e59c 100644
+--- a/auth-options.c
++++ b/auth-options.c
+@@ -242,6 +242,7 @@ sshauthopt_new_with_keys_defaults(void)
+ 	ret->permit_x11_forwarding_flag = 1;
+ 	ret->permit_pty_flag = 1;
+ 	ret->permit_user_rc = 1;
++	ret->permit_tun_flag = 1;
+ 	return ret;
+ }
+
+@@ -345,6 +346,7 @@ sshauthopt_parse(const char *opts, const char **errstrp)
+ 			ret->permit_x11_forwarding_flag = 0;
+ 			ret->permit_pty_flag = 0;
+ 			ret->permit_user_rc = 0;
++			ret->permit_tun_flag = 0;
+ 		} else if ((r = opt_flag("cert-authority", 0, &opts)) != -1) {
+ 			ret->cert_authority = r;
+ 		} else if ((r = opt_flag("port-forwarding", 1, &opts)) != -1) {
+@@ -601,6 +603,7 @@ sshauthopt_merge(const struct sshauthopt *primary,
+ 	OPTFLAG_AND(permit_x11_forwarding_flag);
+ 	OPTFLAG_AND(permit_pty_flag);
+ 	OPTFLAG_AND(permit_user_rc);
++	OPTFLAG_AND(permit_tun_flag);
+ 	OPTFLAG_AND(no_require_user_presence);
+ 	/* Restrictive flags are logical-OR (i.e. must be set in either) */
+ 	OPTFLAG_OR(require_verify);
+@@ -669,6 +672,7 @@ sshauthopt_copy(const struct sshauthopt *orig)
+ 	OPTSCALAR(permit_x11_forwarding_flag);
+ 	OPTSCALAR(permit_pty_flag);
+ 	OPTSCALAR(permit_user_rc);
++	OPTSCALAR(permit_tun_flag);
+ 	OPTSCALAR(restricted);
+ 	OPTSCALAR(cert_authority);
+ 	OPTSCALAR(force_tun_device);
+@@ -804,6 +808,7 @@ sshauthopt_serialise(const struct sshauthopt *opts, struct sshbuf *m,
+ 	    (r = sshbuf_put_u8(m, opts->permit_x11_forwarding_flag)) != 0 ||
+ 	    (r = sshbuf_put_u8(m, opts->permit_pty_flag)) != 0 ||
+ 	    (r = sshbuf_put_u8(m, opts->permit_user_rc)) != 0 ||
++	    (r = sshbuf_put_u8(m, opts->permit_tun_flag)) != 0 ||
+ 	    (r = sshbuf_put_u8(m, opts->restricted)) != 0 ||
+ 	    (r = sshbuf_put_u8(m, opts->cert_authority)) != 0 ||
+ 	    (r = sshbuf_put_u8(m, opts->no_require_user_presence)) != 0 ||
+@@ -867,6 +872,7 @@ sshauthopt_deserialise(struct sshbuf *m, struct sshauthopt **optsp)
+ 	OPT_FLAG(permit_x11_forwarding_flag);
+ 	OPT_FLAG(permit_pty_flag);
+ 	OPT_FLAG(permit_user_rc);
++	OPT_FLAG(permit_tun_flag);
+ 	OPT_FLAG(restricted);
+ 	OPT_FLAG(cert_authority);
+ 	OPT_FLAG(no_require_user_presence);
+diff --git a/auth-options.h b/auth-options.h
+index 6e29b727c..191b9b249 100644
+--- a/auth-options.h
++++ b/auth-options.h
+@@ -39,6 +39,7 @@ struct sshauthopt {
+ 	int permit_x11_forwarding_flag;
+ 	int permit_pty_flag;
+ 	int permit_user_rc;
++	int permit_tun_flag;
+
+ 	/* "restrict" keyword was invoked */
+ 	int restricted;
+diff --git a/serverloop.c b/serverloop.c
+index 8a6e3db80..cf5243f80 100644
+--- a/serverloop.c
++++ b/serverloop.c
+@@ -523,7 +523,8 @@ server_request_tun(struct ssh *ssh)
+ 		ssh_packet_send_debug(ssh, "Unsupported tunnel device mode.");
+ 		return NULL;
+ 	}
+-	if ((options.permit_tun & mode) == 0) {
++	if ((options.permit_tun & mode) == 0 || options.disable_forwarding ||
++	    !auth_opts->permit_tun_flag) {
+ 		ssh_packet_send_debug(ssh, "Server has rejected tunnel device "
+ 		    "forwarding");
+ 		return NULL;

diff --git a/openssh-10.5p1-CVE-2026-73281.patch b/openssh-10.5p1-CVE-2026-73281.patch
new file mode 100644
index 0000000..b59ec35
--- /dev/null
+++ b/openssh-10.5p1-CVE-2026-73281.patch
@@ -0,0 +1,42 @@
+diff --git a/ssh-agent.c b/ssh-agent.c
+--- a/ssh-agent.c
++++ b/ssh-agent.c
+@@ -1839,8 +1839,17 @@ process_extension(SocketEntry *e)
+ 		error_fr(r, "parse");
+ 		goto send;
+ 	}
++
++	/*
++	 * This function can be called while the agent is locked to allow
++	 * session binds to be processed for new channels.
++	 * Other operations should be refused when locked.
++	 */
++
+ 	if (strcmp(name, "session-bind@openssh.com") == 0)
+ 		success = process_ext_session_bind(e);
++	else if (locked)
++		debug_f("attempt to use extension \"%s\" while locked", name);
+ 	else
+ 		debug_f("unsupported extension \"%s\"", name);
+ 	free(name);
+@@ -1892,16 +1901,19 @@ process_message(u_int socknum)
+
+ 	/* check whether agent is locked */
+ 	if (locked && type != SSH_AGENTC_UNLOCK) {
+-		sshbuf_reset(e->request);
+ 		switch (type) {
+ 		case SSH2_AGENTC_REQUEST_IDENTITIES:
+ 			/* send empty lists */
+ 			no_identities(e);
+ 			break;
++		case SSH_AGENTC_EXTENSION:
++			process_extension(e);
++			break;
+ 		default:
+ 			/* send a fail message for all other request types */
+ 			send_status(e, 0);
+ 		}
++		sshbuf_reset(e->request);
+ 		return 1;
+ 	}
+

diff --git a/openssh-10.5p1-CVE-2026-73282.patch b/openssh-10.5p1-CVE-2026-73282.patch
new file mode 100644
index 0000000..a4c4973
--- /dev/null
+++ b/openssh-10.5p1-CVE-2026-73282.patch
@@ -0,0 +1,51 @@
+diff --git a/ssh.c b/ssh.c
+--- a/ssh.c
++++ b/ssh.c
+@@ -1862,14 +1862,24 @@
+ 	}
+ }
+ 
++struct rfwd_confirm_ctx {
++	int fid;
++};
++
+ /* Callback for remote forward global requests */
+ static void
+ ssh_confirm_remote_forward(struct ssh *ssh, int type, u_int32_t seq, void *ctxt)
+ {
+-	struct Forward *rfwd = (struct Forward *)ctxt;
++	struct rfwd_confirm_ctx *rctx = (struct rfwd_confirm_ctx *)ctxt;
++	struct Forward *rfwd;
+ 	u_int port;
+ 	int r;
+ 
++	if (rctx->fid < 0 || rctx->fid >= options.num_remote_forwards)
++		fatal_f("invalid forwarding ID %d", rctx->fid);
++	rfwd = &options.remote_forwards[rctx->fid];
++	freezero(rctx, sizeof(*rctx));
++
+ 	/* XXX verbose() on failure? */
+ 	debug("remote forward %s for: listen %s%s%d, connect %s:%d",
+ 	    type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure",
+@@ -2047,6 +2057,8 @@
+ 
+ 	/* Initiate remote TCP/IP port forwardings. */
+ 	for (i = 0; i < options.num_remote_forwards; i++) {
++		struct rfwd_confirm_ctx *rctx;
++
+ 		debug("Remote connections from %.200s:%d forwarded to "
+ 		    "local address %.200s:%d",
+ 		    (options.remote_forwards[i].listen_path != NULL) ?
+@@ -2061,9 +2073,10 @@
+ 		if ((options.remote_forwards[i].handle =
+ 		    channel_request_remote_forwarding(ssh,
+ 		    &options.remote_forwards[i])) >= 0) {
++			rctx = xcalloc(1, sizeof(*rctx));
++			rctx->fid = i;
+ 			client_register_global_confirm(
+-			    ssh_confirm_remote_forward,
+-			    &options.remote_forwards[i]);
++			    ssh_confirm_remote_forward, rctx);
+ 			forward_confirms_pending++;
+ 		} else if (options.exit_on_forward_failure)
+ 			fatal("Could not request remote forwarding.");

diff --git a/openssh-7.2p2-x11.patch b/openssh-7.2p2-x11.patch
index 6db16be..a605a41 100644
--- a/openssh-7.2p2-x11.patch
+++ b/openssh-7.2p2-x11.patch
@@ -32,7 +32,7 @@ diff --git a/channels.c b/channels.c
  	return -1;
  }
 
-@@ -5099,8 +5102,18 @@
+@@ -5099,8 +5102,19 @@
  connect_local_xsocket(u_int dnr)
  {
  	char buf[1024];
@@ -41,10 +41,11 @@ diff --git a/channels.c b/channels.c
 +	int len, ret;
 +	len = snprintf(buf + 1, sizeof (buf) - 1, _PATH_UNIX_X, dnr);
 +#ifdef linux
-+	/* try abstract socket first */
-+	buf[0] = '\0';
-+	if ((ret = connect_local_xsocket_path(buf, len + 1)) >= 0)
-+		return ret;
++	if (getenv("SSH_INSECURE_ABSTRACT_SOCKET_ENABLED") != NULL) {
++		buf[0] = '\0';
++		if ((ret = connect_local_xsocket_path(buf, len + 1)) >= 0)
++			return ret;
++	}
 +#endif
 +	if ((ret = connect_local_xsocket_path(buf + 1, len)) >= 0)
 +		return ret;

diff --git a/openssh-7.7p1-fips.patch b/openssh-7.7p1-fips.patch
index 8d442a4..bc44ef3 100644
--- a/openssh-7.7p1-fips.patch
+++ b/openssh-7.7p1-fips.patch
@@ -106,17 +106,18 @@ diff -up openssh-8.6p1/kexgexc.c.fips openssh-8.6p1/kexgexc.c
  #include <sys/types.h>
  
  #include <openssl/dh.h>
-@@ -115,6 +116,10 @@ input_kex_dh_gex_group(int type, u_int32
- 		r = SSH_ERR_ALLOC_FAIL;
- 		goto out;
+@@ -117,6 +118,11 @@ input_kex_dh_gex_group(int type, u_int32
  	}
+ 	p = g = NULL; /* belong to kex->dh now */
+ 
 +	if (FIPS_mode() && dh_is_known_group(kex->dh) == 0) {
 +		r = SSH_ERR_INVALID_ARGUMENT;
 +		goto out;
 +	}
- 	p = g = NULL; /* belong to kex->dh now */
- 
++
  	/* generate and send 'e', client DH public key */
+ 	if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0)
+ 		goto out;
 diff -up openssh-8.6p1/myproposal.h.fips openssh-8.6p1/myproposal.h
 --- openssh-8.6p1/myproposal.h.fips	2021-04-16 05:55:25.000000000 +0200
 +++ openssh-8.6p1/myproposal.h	2021-05-06 12:08:36.498926877 +0200

diff --git a/openssh-9.9p1-CVE-2026-60001.patch b/openssh-9.9p1-CVE-2026-60001.patch
new file mode 100644
index 0000000..27eecc8
--- /dev/null
+++ b/openssh-9.9p1-CVE-2026-60001.patch
@@ -0,0 +1,97 @@
+diff --color -ruNp a/auth2.c b/auth2.c
+--- a/auth2.c	2026-09-17 15:21:59.317492134 +0200
++++ b/auth2.c	2026-09-17 15:29:58.698877649 +0200
+@@ -267,6 +267,12 @@ ensure_minimum_time_since(double start,
+ 	nanosleep(&ts, NULL);
+ }
+ 
++void
++auth_failure_delay(Authctxt *authctxt, double tstart)
++{
++	ensure_minimum_time_since(tstart, user_specific_delay(authctxt->user));
++}
++
+ static int
+ input_userauth_request(int type, u_int32_t seq, struct ssh *ssh)
+ {
+@@ -359,8 +365,8 @@ input_userauth_request(int type, u_int32
+ 		authenticated =	m->userauth(ssh, method);
+ 	}
+ 	if (!authctxt->authenticated && strcmp(method, "none") != 0)
+-		ensure_minimum_time_since(tstart,
+-		    user_specific_delay(authctxt->user));
++		auth_failure_delay(authctxt, tstart);
++
+ 	userauth_finish(ssh, authenticated, method, NULL);
+ 	r = 0;
+  out:
+diff --color -ruNp a/auth2-chall.c b/auth2-chall.c
+--- a/auth2-chall.c	2024-09-20 00:20:48.000000000 +0200
++++ b/auth2-chall.c	2026-09-17 15:24:34.321075436 +0200
+@@ -296,6 +296,7 @@ input_userauth_info_response(int type, u
+ 	u_int i, nresp;
+ 	const char *devicename = NULL;
+ 	char **response = NULL;
++	double tstart = monotime_double();
+ 
+ 	if (authctxt == NULL)
+ 		fatal_f("no authctxt");
+@@ -354,6 +355,9 @@ input_userauth_info_response(int type, u
+ 			auth2_challenge_start(ssh);
+ 		}
+ 	}
++
++	if (!authenticated)
++		auth_failure_delay(authctxt, tstart);
+ 	userauth_finish(ssh, authenticated, "keyboard-interactive",
+ 	    devicename);
+ 	return 0;
+diff --color -ruNp a/auth2-gss.c b/auth2-gss.c
+--- a/auth2-gss.c	2026-09-17 15:21:59.236281062 +0200
++++ b/auth2-gss.c	2026-09-17 15:27:33.902644227 +0200
+@@ -298,6 +298,7 @@ input_gssapi_exchange_complete(int type,
+ {
+ 	Authctxt *authctxt = ssh->authctxt;
+ 	int r, authenticated;
++	double tstart = monotime_double();
+ 
+ 	if (authctxt == NULL)
+ 		fatal("No authentication or GSSAPI context");
+@@ -311,6 +312,8 @@ input_gssapi_exchange_complete(int type,
+ 		fatal_fr(r, "parse packet");
+ 
+  	authenticated = mm_ssh_gssapi_userok(authctxt->user, authctxt->pw, 1);
++	if (!authenticated)
++		auth_failure_delay(authctxt, tstart);
+ 
+ 	authctxt->postponed = 0;
+ 	ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
+@@ -332,6 +335,7 @@ input_gssapi_mic(int type, u_int32_t ple
+ 	gss_buffer_desc mic, gssbuf;
+ 	u_char *p;
+ 	size_t len;
++	double tstart = monotime_double();
+ 
+ 	if (authctxt == NULL)
+ 		fatal("No authentication or GSSAPI context");
+@@ -367,6 +371,9 @@ input_gssapi_mic(int type, u_int32_t ple
+ 		free(micuser);
+ 	free(mic.value);
+ 
++	if (!authenticated)
++		auth_failure_delay(authctxt, tstart);
++
+ 	authctxt->postponed = 0;
+ 	ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
+ 	ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
+diff --color -ruNp a/auth.h b/auth.h
+--- a/auth.h	2026-09-17 15:21:59.318365032 +0200
++++ b/auth.h	2026-09-17 15:23:03.388812848 +0200
+@@ -179,6 +179,7 @@ void	auth_log(struct ssh *, int, int, co
+ void	auth_maxtries_exceeded(struct ssh *) __attribute__((noreturn));
+ void	userauth_finish(struct ssh *, int, const char *, const char *);
+ int	auth_root_allowed(struct ssh *, const char *);
++void   auth_failure_delay(Authctxt *, double);
+ 
+ char	*auth2_read_banner(void);
+ int	 auth2_methods_valid(const char *, int);

diff --git a/openssh-9.9p1-copy-data-ext-self-copy.patch b/openssh-9.9p1-copy-data-ext-self-copy.patch
new file mode 100644
index 0000000..1fa43fc
--- /dev/null
+++ b/openssh-9.9p1-copy-data-ext-self-copy.patch
@@ -0,0 +1,51 @@
+diff --color -ruNp a/sftp-server.c b/sftp-server.c
+--- a/sftp-server.c	2026-07-17 16:23:12.293427062 +0200
++++ b/sftp-server.c	2026-07-17 16:29:01.480535500 +0200
+@@ -1625,6 +1625,7 @@ process_extended_copy_data(u_int32_t id)
+ 	u_int64_t len, read_off, read_len, write_off;
+ 	int r, copy_until_eof, status = SSH2_FX_OP_UNSUPPORTED;
+ 	size_t ret;
++	struct stat st_read, st_write;
+ 
+ 	if ((r = get_handle(iqueue, &read_handle)) != 0 ||
+ 	    (r = sshbuf_get_u64(iqueue, &read_off)) != 0 ||
+@@ -1647,12 +1648,35 @@ process_extended_copy_data(u_int32_t id)
+ 	} else
+ 		copy_until_eof = 0;
+ 
++	/* Disallow reading & writing to the same handle, path or inode */
+ 	read_fd = handle_to_fd(read_handle);
+ 	write_fd = handle_to_fd(write_handle);
+-
+-	/* Disallow reading & writing to the same handle or same path or dirs */
+-	if (read_handle == write_handle || read_fd < 0 || write_fd < 0 ||
+-	    !strcmp(handle_to_name(read_handle), handle_to_name(write_handle))) {
++	if (read_fd < 0 || write_fd < 0) {
++		error_f("bad read or write fd");
++		status = errno_to_portable(EBADF);
++		goto out;
++	}
++	if (fstat(read_fd, &st_read) != 0) {
++		status = errno_to_portable(errno);
++		error_f("fstat read_fd failed: %s", strerror(errno));
++		goto out;
++	}
++	if (fstat(write_fd, &st_write) != 0) {
++		status = errno_to_portable(errno);
++		error_f("fstat write_fd failed: %s", strerror(errno));
++		goto out;
++	}
++	if (read_handle == write_handle ||
++	    !strcmp(handle_to_name(read_handle), handle_to_name(write_handle)) ||
++	    (st_read.st_dev != 0 && st_read.st_ino != 0 &&
++	    st_read.st_dev == st_write.st_dev &&
++	    st_read.st_ino == st_write.st_ino)) {
++		error_f("refusing to read/write same file: "
++		    "read \"%s\" dev %lu ino %lu, write \"%s\" dev %lu ino %lu",
++		    handle_to_name(read_handle),
++		    (u_long)st_read.st_dev, (u_long)st_read.st_ino,
++		    handle_to_name(write_handle),
++		    (u_long)st_write.st_dev, (u_long)st_write.st_ino);
+ 		status = SSH2_FX_FAILURE;
+ 		goto out;
+ 	}

diff --git a/openssh-9.9p1-cve-2026-60002.patch b/openssh-9.9p1-cve-2026-60002.patch
new file mode 100644
index 0000000..ab16479
--- /dev/null
+++ b/openssh-9.9p1-cve-2026-60002.patch
@@ -0,0 +1,191 @@
+diff --color -ruNp a/ssh.c b/ssh.c
+--- a/ssh.c	2026-07-14 11:58:09.036496915 +0200
++++ b/ssh.c	2026-07-14 12:00:55.044542741 +0200
+@@ -619,26 +619,6 @@ set_addrinfo_port(struct addrinfo *addrs
+ 	}
+ }
+ 
+-static void
+-ssh_conn_info_free(struct ssh_conn_info *cinfo)
+-{
+-	if (cinfo == NULL)
+-		return;
+-	free(cinfo->conn_hash_hex);
+-	free(cinfo->shorthost);
+-	free(cinfo->uidstr);
+-	free(cinfo->keyalias);
+-	free(cinfo->thishost);
+-	free(cinfo->host_arg);
+-	free(cinfo->portstr);
+-	free(cinfo->remhost);
+-	free(cinfo->remuser);
+-	free(cinfo->homedir);
+-	free(cinfo->locuser);
+-	free(cinfo->jmphost);
+-	free(cinfo);
+-}
+-
+ /*
+  * Main program for the ssh client.
+  */
+@@ -1765,8 +1745,8 @@ main(int ac, char **av)
+ 	ssh_signal(SIGCHLD, main_sigchld_handler);
+ 
+ 	/* Log into the remote system.  Never returns if the login fails. */
+-	ssh_login(ssh, &sensitive_data, host, (struct sockaddr *)&hostaddr,
+-	    options.port, pw, timeout_ms, cinfo);
++	ssh_login(ssh, &sensitive_data, host, &hostaddr, options.port,
++	    pw, timeout_ms, cinfo);
+ 
+ 	/* We no longer need the private host keys.  Clear them now. */
+ 	if (sensitive_data.nkeys != 0) {
+diff --color -ruNp a/sshconnect2.c b/sshconnect2.c
+--- a/sshconnect2.c	2026-07-14 11:58:09.031477028 +0200
++++ b/sshconnect2.c	2026-07-14 12:01:56.374803123 +0200
+@@ -89,7 +89,7 @@ extern Options options;
+  */
+ 
+ static char *xxx_host;
+-static struct sockaddr *xxx_hostaddr;
++static struct sockaddr_storage xxx_hostaddr;
+ static const struct ssh_conn_info *xxx_conn_info;
+ static int key_type_allowed(struct sshkey *, const char *);
+ 
+@@ -105,7 +105,7 @@ verify_host_key_callback(struct sshkey *
+ 		fatal("Server host key %s not in HostKeyAlgorithms",
+ 		    sshkey_ssh_name(hostkey));
+ 	}
+-	if (verify_host_key(xxx_host, xxx_hostaddr, hostkey,
++	if (verify_host_key(xxx_host, (struct sockaddr *)&xxx_hostaddr, hostkey,
+ 	    xxx_conn_info) != 0)
+ 		fatal("Host key verification failed.");
+ 	return 0;
+@@ -222,8 +222,8 @@ order_hostkeyalgs(char *host, struct soc
+ }
+ 
+ void
+-ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port,
+-    const struct ssh_conn_info *cinfo)
++ssh_kex2(struct ssh *ssh, char *host, struct sockaddr_storage *hostaddr,
++    u_short port, const struct ssh_conn_info *cinfo)
+ {
+ 	char *myproposal[PROPOSAL_MAX];
+ 	char *all_key, *hkalgs = NULL, *filtered_algs = NULL;
+@@ -234,9 +234,9 @@ ssh_kex2(struct ssh *ssh, char *host, st
+ 	char *gss_host = NULL;
+ #endif
+ 
+-	xxx_host = host;
+-	xxx_hostaddr = hostaddr;
+-	xxx_conn_info = cinfo;
++	xxx_host = xstrdup(host);
++	xxx_hostaddr = *hostaddr;
++	xxx_conn_info = ssh_conn_info_dup(cinfo);
+ 
+ 	if (options.rekey_limit || options.rekey_interval)
+ 		ssh_packet_set_rekey_limits(ssh, options.rekey_limit,
+@@ -259,8 +259,10 @@ ssh_kex2(struct ssh *ssh, char *host, st
+ 		fatal_fr(r, "kex_assemble_namelist");
+ 	free(all_key);
+ 
+-	if (use_known_hosts_order)
+-		hkalgs = order_hostkeyalgs(host, hostaddr, port, cinfo);
++	if (use_known_hosts_order) {
++		hkalgs = order_hostkeyalgs(host, (struct sockaddr *)hostaddr,
++		    port, cinfo);
++	}
+ 
+ 	filtered_algs = hkalgs ? match_filter_allowlist(hkalgs, options.pubkey_accepted_algos)
+ 		               : match_filter_allowlist(options.hostkeyalgorithms,
+diff --color -ruNp a/sshconnect.c b/sshconnect.c
+--- a/sshconnect.c	2026-07-14 11:58:08.892659011 +0200
++++ b/sshconnect.c	2026-07-14 12:00:55.045767462 +0200
+@@ -84,6 +84,49 @@ extern char *__progname;
+ static int show_other_keys(struct hostkeys *, struct sshkey *);
+ static void warn_changed_key(struct sshkey *);
+ 
++void
++ssh_conn_info_free(struct ssh_conn_info *cinfo)
++{
++	if (cinfo == NULL)
++		return;
++	free(cinfo->conn_hash_hex);
++	free(cinfo->shorthost);
++	free(cinfo->uidstr);
++	free(cinfo->keyalias);
++	free(cinfo->thishost);
++	free(cinfo->host_arg);
++	free(cinfo->portstr);
++	free(cinfo->remhost);
++	free(cinfo->remuser);
++	free(cinfo->homedir);
++	free(cinfo->locuser);
++	free(cinfo->jmphost);
++	freezero(cinfo, sizeof(*cinfo));
++}
++
++struct ssh_conn_info *
++ssh_conn_info_dup(const struct ssh_conn_info *cinfo)
++{
++	struct ssh_conn_info *ret;
++
++	if (cinfo == NULL)
++		return NULL;
++	ret = xcalloc(1, sizeof(*ret));
++	ret->conn_hash_hex = xstrdup(cinfo->conn_hash_hex);
++	ret->shorthost = xstrdup(cinfo->shorthost);
++	ret->uidstr = xstrdup(cinfo->uidstr);
++	ret->keyalias = xstrdup(cinfo->keyalias);
++	ret->thishost = xstrdup(cinfo->thishost);
++	ret->host_arg = xstrdup(cinfo->host_arg);
++	ret->portstr = xstrdup(cinfo->portstr);
++	ret->remhost = xstrdup(cinfo->remhost);
++	ret->remuser = xstrdup(cinfo->remuser);
++	ret->homedir = xstrdup(cinfo->homedir);
++	ret->locuser = xstrdup(cinfo->locuser);
++	ret->jmphost = xstrdup(cinfo->jmphost);
++	return ret;
++}
++
+ /* Expand a proxy command */
+ static char *
+ expand_proxy_command(const char *proxy_command, const char *user,
+@@ -1589,8 +1632,8 @@ out:
+  */
+ void
+ ssh_login(struct ssh *ssh, Sensitive *sensitive, const char *orighost,
+-    struct sockaddr *hostaddr, u_short port, struct passwd *pw, int timeout_ms,
+-    const struct ssh_conn_info *cinfo)
++    struct sockaddr_storage *hostaddr, u_short port, struct passwd *pw,
++    int timeout_ms, const struct ssh_conn_info *cinfo)
+ {
+ 	char *host;
+ 	char *server_user, *local_user;
+diff --color -ruNp a/sshconnect.h b/sshconnect.h
+--- a/sshconnect.h	2024-09-20 00:20:48.000000000 +0200
++++ b/sshconnect.h	2026-07-14 12:00:55.045948953 +0200
+@@ -73,7 +73,7 @@ int	 ssh_connect(struct ssh *, const cha
+ void	 ssh_kill_proxy_command(void);
+ 
+ void	 ssh_login(struct ssh *, Sensitive *, const char *,
+-    struct sockaddr *, u_short, struct passwd *, int,
++    struct sockaddr_storage *, u_short, struct passwd *, int,
+     const struct ssh_conn_info *);
+ 
+ int	 verify_host_key(char *, struct sockaddr *, struct sshkey *,
+@@ -82,7 +82,7 @@ int	 verify_host_key(char *, struct sock
+ void	 get_hostfile_hostname_ipaddr(char *, struct sockaddr *, u_short,
+     char **, char **);
+ 
+-void	 ssh_kex2(struct ssh *ssh, char *, struct sockaddr *, u_short,
++void	 ssh_kex2(struct ssh *ssh, char *, struct sockaddr_storage *, u_short,
+     const struct ssh_conn_info *);
+ 
+ void	 ssh_userauth2(struct ssh *ssh, const char *, const char *,
+@@ -98,3 +98,6 @@ void	 load_hostkeys_command(struct hostk
+     const struct sshkey *, const char *);
+ 
+ int hostkey_accepted_by_hostkeyalgs(const struct sshkey *);
++
++void ssh_conn_info_free(struct ssh_conn_info *);
++struct ssh_conn_info *ssh_conn_info_dup(const struct ssh_conn_info *);

diff --git a/openssh-9.9p1-gsissh.patch b/openssh-9.9p1-gsissh.patch
index 8abb9e8..24f5c02 100644
--- a/openssh-9.9p1-gsissh.patch
+++ b/openssh-9.9p1-gsissh.patch
@@ -1,7 +1,7 @@
 diff -Nur openssh-9.9p1.orig/auth2.c openssh-9.9p1/auth2.c
---- openssh-9.9p1.orig/auth2.c	2026-03-25 09:33:50.361694147 +0100
-+++ openssh-9.9p1/auth2.c	2026-03-25 09:34:38.081444879 +0100
-@@ -286,7 +286,28 @@
+--- openssh-9.9p1.orig/auth2.c	2026-09-22 11:11:59.980257631 +0200
++++ openssh-9.9p1/auth2.c	2026-09-22 11:12:32.492921127 +0200
+@@ -292,7 +292,28 @@
  	    (r = sshpkt_get_cstring(ssh, &service, NULL)) != 0 ||
  	    (r = sshpkt_get_cstring(ssh, &method, NULL)) != 0)
  		goto out;
@@ -31,7 +31,7 @@ diff -Nur openssh-9.9p1.orig/auth2.c openssh-9.9p1/auth2.c
  	debug("attempt %d failures %d", authctxt->attempt, authctxt->failures);
  
  #ifdef WITH_SELINUX
-@@ -299,11 +320,33 @@
+@@ -305,11 +326,33 @@
  
  	if (authctxt->attempt >= 1024)
  		auth_maxtries_exceeded(ssh);
@@ -69,7 +69,7 @@ diff -Nur openssh-9.9p1.orig/auth2.c openssh-9.9p1/auth2.c
  			authctxt->valid = 1;
  			debug2_f("setting up authctxt for %s", user);
  		} else {
-@@ -311,6 +354,9 @@
+@@ -317,6 +360,9 @@
  			/* Invalid user, fake password information */
  			authctxt->pw = fakepw();
  		}
@@ -79,7 +79,7 @@ diff -Nur openssh-9.9p1.orig/auth2.c openssh-9.9p1/auth2.c
  #ifdef USE_PAM
  		if (options.use_pam)
  			mm_start_pam(ssh);
-@@ -318,6 +364,7 @@
+@@ -324,6 +370,7 @@
  		ssh_packet_set_log_preamble(ssh, "%suser %s",
  		    authctxt->valid ? "authenticating " : "invalid ", user);
  		setproctitle("%s [net]", authctxt->valid ? user : "unknown");
@@ -87,7 +87,7 @@ diff -Nur openssh-9.9p1.orig/auth2.c openssh-9.9p1/auth2.c
  		authctxt->service = xstrdup(service);
  		authctxt->style = style ? xstrdup(style) : NULL;
  #ifdef WITH_SELINUX
-@@ -333,9 +380,10 @@
+@@ -339,9 +386,10 @@
  		if (auth2_setup_methods_lists(authctxt) != 0)
  			ssh_packet_disconnect(ssh,
  			    "no authentication methods enabled");
@@ -102,8 +102,8 @@ diff -Nur openssh-9.9p1.orig/auth2.c openssh-9.9p1/auth2.c
  		    authctxt->user, authctxt->service, user, service);
  	}
 diff -Nur openssh-9.9p1.orig/auth2-gss.c openssh-9.9p1/auth2-gss.c
---- openssh-9.9p1.orig/auth2-gss.c	2026-03-25 09:33:50.247721032 +0100
-+++ openssh-9.9p1/auth2-gss.c	2026-03-25 09:34:38.082271174 +0100
+--- openssh-9.9p1.orig/auth2-gss.c	2026-09-22 11:11:59.981302698 +0200
++++ openssh-9.9p1/auth2-gss.c	2026-09-22 11:22:00.615962500 +0200
 @@ -54,6 +54,7 @@
  extern struct authmethod_cfg methodcfg_gsskeyex;
  extern struct authmethod_cfg methodcfg_gssapi;
@@ -228,12 +228,13 @@ diff -Nur openssh-9.9p1.orig/auth2-gss.c openssh-9.9p1/auth2-gss.c
  /*
   * This is called when the client thinks we've completed authentication.
   * It should only be enabled in the dispatch handler by the function above,
-@@ -297,11 +347,13 @@
+@@ -297,12 +347,14 @@
  input_gssapi_exchange_complete(int type, u_int32_t plen, struct ssh *ssh)
  {
  	Authctxt *authctxt = ssh->authctxt;
 -	int r, authenticated;
 +	int r, authenticated = 0;
+ 	double tstart = monotime_double();
  
  	if (authctxt == NULL)
  		fatal("No authentication or GSSAPI context");
@@ -243,7 +244,7 @@ diff -Nur openssh-9.9p1.orig/auth2-gss.c openssh-9.9p1/auth2-gss.c
  	/*
  	 * We don't need to check the status, because we're only enabled in
  	 * the dispatcher once the exchange is complete
-@@ -310,7 +362,11 @@
+@@ -311,7 +363,11 @@
  	if ((r = sshpkt_get_end(ssh)) != 0)
  		fatal_fr(r, "parse packet");
  
@@ -253,10 +254,10 @@ diff -Nur openssh-9.9p1.orig/auth2-gss.c openssh-9.9p1/auth2-gss.c
 +		authenticated = mm_ssh_gssapi_userok(authctxt->user,
 +		    authctxt->pw, 1);
 +	}
+ 	if (!authenticated)
+ 		auth_failure_delay(authctxt, tstart);
  
- 	authctxt->postponed = 0;
- 	ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
-@@ -357,10 +413,16 @@
+@@ -361,10 +417,16 @@
  		fatal_f("sshbuf_mutable_ptr failed");
  	gssbuf.length = sshbuf_len(b);
  
@@ -276,7 +277,7 @@ diff -Nur openssh-9.9p1.orig/auth2-gss.c openssh-9.9p1/auth2-gss.c
  
  	sshbuf_free(b);
  	if (micuser != authctxt->user)
-@@ -376,6 +438,26 @@
+@@ -383,6 +445,26 @@
  	return 0;
  }
  
@@ -304,8 +305,8 @@ diff -Nur openssh-9.9p1.orig/auth2-gss.c openssh-9.9p1/auth2-gss.c
  	&methodcfg_gsskeyex,
  	userauth_gsskeyex,
 diff -Nur openssh-9.9p1.orig/auth.c openssh-9.9p1/auth.c
---- openssh-9.9p1.orig/auth.c	2026-03-25 09:33:50.448829611 +0100
-+++ openssh-9.9p1/auth.c	2026-03-25 09:34:38.082867201 +0100
+--- openssh-9.9p1.orig/auth.c	2026-09-22 11:11:59.920534332 +0200
++++ openssh-9.9p1/auth.c	2026-09-22 11:12:32.495347014 +0200
 @@ -298,7 +298,8 @@
  	    method,
  	    submethod != NULL ? "/" : "", submethod == NULL ? "" : submethod,
@@ -337,8 +338,8 @@ diff -Nur openssh-9.9p1.orig/auth.c openssh-9.9p1/auth.c
  		record_failed_login(ssh, user,
  		    auth_get_canonical_hostname(ssh, options.use_dns), "ssh");
 diff -Nur openssh-9.9p1.orig/auth.h openssh-9.9p1/auth.h
---- openssh-9.9p1.orig/auth.h	2026-03-25 09:33:50.363107669 +0100
-+++ openssh-9.9p1/auth.h	2026-03-25 09:34:38.083836881 +0100
+--- openssh-9.9p1.orig/auth.h	2026-09-22 11:11:59.981590619 +0200
++++ openssh-9.9p1/auth.h	2026-09-22 11:12:32.496447136 +0200
 @@ -85,6 +85,8 @@
  	krb5_principal	 krb5_user;
  	char		*krb5_ticket_file;
@@ -349,8 +350,8 @@ diff -Nur openssh-9.9p1.orig/auth.h openssh-9.9p1/auth.h
  #endif
  	struct sshbuf	*loginmsg;
 diff -Nur openssh-9.9p1.orig/auth-pam.c openssh-9.9p1/auth-pam.c
---- openssh-9.9p1.orig/auth-pam.c	2026-03-25 09:33:50.403888480 +0100
-+++ openssh-9.9p1/auth-pam.c	2026-03-25 09:34:38.084567702 +0100
+--- openssh-9.9p1.orig/auth-pam.c	2026-09-22 11:11:59.871925590 +0200
++++ openssh-9.9p1/auth-pam.c	2026-09-22 11:12:32.497276479 +0200
 @@ -248,6 +248,7 @@
  static const char *sshpam_password = NULL;
  static char *sshpam_rhost = NULL;
@@ -512,8 +513,8 @@ diff -Nur openssh-9.9p1.orig/auth-pam.c openssh-9.9p1/auth-pam.c
  	free(fake);
  	if (sshpam_err == PAM_MAXTRIES)
 diff -Nur openssh-9.9p1.orig/auth-pam.h openssh-9.9p1/auth-pam.h
---- openssh-9.9p1.orig/auth-pam.h	2026-03-25 09:33:50.214552807 +0100
-+++ openssh-9.9p1/auth-pam.h	2026-03-25 09:34:38.085447286 +0100
+--- openssh-9.9p1.orig/auth-pam.h	2026-09-22 11:11:59.682913412 +0200
++++ openssh-9.9p1/auth-pam.h	2026-09-22 11:12:32.498665667 +0200
 @@ -43,5 +43,6 @@
  int sshpam_get_maxtries_reached(void);
  void sshpam_set_maxtries_reached(int);
@@ -522,8 +523,8 @@ diff -Nur openssh-9.9p1.orig/auth-pam.h openssh-9.9p1/auth-pam.h
  
  #endif /* USE_PAM */
 diff -Nur openssh-9.9p1.orig/canohost.c openssh-9.9p1/canohost.c
---- openssh-9.9p1.orig/canohost.c	2026-03-25 09:33:50.249000599 +0100
-+++ openssh-9.9p1/canohost.c	2026-03-25 09:34:38.085680697 +0100
+--- openssh-9.9p1.orig/canohost.c	2026-09-22 11:11:59.719484447 +0200
++++ openssh-9.9p1/canohost.c	2026-09-22 11:12:32.499010251 +0200
 @@ -17,6 +17,7 @@
  #include <sys/types.h>
  #include <sys/socket.h>
@@ -567,8 +568,8 @@ diff -Nur openssh-9.9p1.orig/canohost.c openssh-9.9p1/canohost.c
 +	}
 +}
 diff -Nur openssh-9.9p1.orig/canohost.h openssh-9.9p1/canohost.h
---- openssh-9.9p1.orig/canohost.h	2026-03-25 09:33:50.249246231 +0100
-+++ openssh-9.9p1/canohost.h	2026-03-25 09:34:38.086742916 +0100
+--- openssh-9.9p1.orig/canohost.h	2026-09-22 11:11:59.719668822 +0200
++++ openssh-9.9p1/canohost.h	2026-09-22 11:12:32.499482192 +0200
 @@ -26,4 +26,6 @@
  
  #endif /* _CANOHOST_H */
@@ -577,8 +578,8 @@ diff -Nur openssh-9.9p1.orig/canohost.h openssh-9.9p1/canohost.h
 +
  void		 ipv64_normalise_mapped(struct sockaddr_storage *, socklen_t *);
 diff -Nur openssh-9.9p1.orig/configure.ac openssh-9.9p1/configure.ac
---- openssh-9.9p1.orig/configure.ac	2026-03-25 09:33:50.437117119 +0100
-+++ openssh-9.9p1/configure.ac	2026-03-25 09:34:38.087853187 +0100
+--- openssh-9.9p1.orig/configure.ac	2026-09-22 11:11:59.908925585 +0200
++++ openssh-9.9p1/configure.ac	2026-09-22 11:12:32.500161138 +0200
 @@ -4920,6 +4920,14 @@
  				AC_CHECK_HEADER([gssapi_krb5.h], ,
  						[ CPPFLAGS="$oldCPP" ])
@@ -636,8 +637,8 @@ diff -Nur openssh-9.9p1.orig/configure.ac openssh-9.9p1/configure.ac
  
  PRIVSEP_PATH=/var/empty
 diff -Nur openssh-9.9p1.orig/gss-genr.c openssh-9.9p1/gss-genr.c
---- openssh-9.9p1.orig/gss-genr.c	2026-03-25 09:33:50.470463510 +0100
-+++ openssh-9.9p1/gss-genr.c	2026-03-25 09:34:38.089271110 +0100
+--- openssh-9.9p1.orig/gss-genr.c	2026-09-22 11:11:59.983990516 +0200
++++ openssh-9.9p1/gss-genr.c	2026-09-22 11:12:32.502916899 +0200
 @@ -41,6 +41,7 @@
  #include "ssherr.h"
  #include "sshbuf.h"
@@ -675,8 +676,8 @@ diff -Nur openssh-9.9p1.orig/gss-genr.c openssh-9.9p1/gss-genr.c
  	return (ctx->major);
  }
 diff -Nur openssh-9.9p1.orig/gss-serv.c openssh-9.9p1/gss-serv.c
---- openssh-9.9p1.orig/gss-serv.c	2026-03-25 09:33:50.463850077 +0100
-+++ openssh-9.9p1/gss-serv.c	2026-03-25 09:34:38.090680651 +0100
+--- openssh-9.9p1.orig/gss-serv.c	2026-09-22 11:11:59.935043523 +0200
++++ openssh-9.9p1/gss-serv.c	2026-09-22 11:12:32.503802139 +0200
 @@ -50,10 +50,12 @@
  #include "monitor_wrap.h"
  
@@ -759,15 +760,15 @@ diff -Nur openssh-9.9p1.orig/gss-serv.c openssh-9.9p1/gss-serv.c
  /* Extract authentication indicators from the Kerberos ticket. Authentication
   * indicators are GSSAPI name attributes for the name "auth-indicators".
   * Multiple indicators might be present in the ticket.
-@@ -379,6 +412,7 @@
- 	(void) gss_release_buffer_set(&ctx->minor, &attrs);
- 	return (ctx->major);
+@@ -387,6 +420,7 @@
+ 	gss_release_buffer_set(&ctx->minor, &attrs);
+ 	return ctx->major;
  }
 +#endif
  
  /* Extract the client details from a given context. This can only reliably
   * be called once for a context */
-@@ -394,21 +428,24 @@
+@@ -401,21 +435,24 @@
  	gss_buffer_desc ename = GSS_C_EMPTY_BUFFER;
  
  	if (options.gss_store_rekey && client->used && ctx->client_creds) {
@@ -797,7 +798,7 @@ diff -Nur openssh-9.9p1.orig/gss-serv.c openssh-9.9p1/gss-serv.c
  		    new_name, &equal);
  
  		if (GSS_ERROR(ctx->major)) {
-@@ -423,9 +460,9 @@
+@@ -430,9 +467,9 @@
  
  		debug("Marking rekeyed credentials for export");
  
@@ -809,7 +810,7 @@ diff -Nur openssh-9.9p1.orig/gss-serv.c openssh-9.9p1/gss-serv.c
  		client->creds = ctx->client_creds;
  		ctx->client_creds = GSS_C_NO_CREDENTIAL;
  		client->updated = 1;
-@@ -442,12 +479,17 @@
+@@ -449,12 +486,17 @@
  		i++;
  	}
  
@@ -829,7 +830,7 @@ diff -Nur openssh-9.9p1.orig/gss-serv.c openssh-9.9p1/gss-serv.c
  		ssh_gssapi_error(ctx);
  		return (ctx->major);
  	}
-@@ -464,22 +506,33 @@
+@@ -471,22 +513,33 @@
  		return (ctx->major);
  	}
  
@@ -864,7 +865,7 @@ diff -Nur openssh-9.9p1.orig/gss-serv.c openssh-9.9p1/gss-serv.c
  	return (ctx->major);
  }
  
-@@ -487,6 +540,7 @@
+@@ -494,6 +547,7 @@
  void
  ssh_gssapi_cleanup_creds(void)
  {
@@ -872,7 +873,7 @@ diff -Nur openssh-9.9p1.orig/gss-serv.c openssh-9.9p1/gss-serv.c
  	krb5_ccache ccache = NULL;
  	krb5_error_code problem;
  
-@@ -502,6 +556,14 @@
+@@ -509,6 +563,14 @@
  			gssapi_client.store.data = NULL;
  		}
  	}
@@ -887,7 +888,7 @@ diff -Nur openssh-9.9p1.orig/gss-serv.c openssh-9.9p1/gss-serv.c
  }
  
  /* As user */
-@@ -514,6 +576,11 @@
+@@ -521,6 +583,11 @@
  	}
  
  	if (gssapi_client.mech && gssapi_client.mech->storecreds) {
@@ -899,7 +900,7 @@ diff -Nur openssh-9.9p1.orig/gss-serv.c openssh-9.9p1/gss-serv.c
  		return (*gssapi_client.mech->storecreds)(&gssapi_client);
  	} else
  		debug("ssh_gssapi_storecreds: Not a GSSAPI mechanism");
-@@ -547,11 +614,13 @@
+@@ -554,11 +621,13 @@
  
  	(void) kex; /* used in privilege separation */
  
@@ -916,7 +917,7 @@ diff -Nur openssh-9.9p1.orig/gss-serv.c openssh-9.9p1/gss-serv.c
  	if (gssapi_client.mech && gssapi_client.mech->userok)
  		if ((*gssapi_client.mech->userok)(&gssapi_client, user)) {
  			gssapi_client.used = 1;
-@@ -562,6 +631,7 @@
+@@ -569,6 +638,7 @@
  			gss_release_buffer(&lmin, &gssapi_client.displayname);
  			gss_release_buffer(&lmin, &gssapi_client.exportedname);
  			gss_release_cred(&lmin, &gssapi_client.creds);
@@ -924,7 +925,7 @@ diff -Nur openssh-9.9p1.orig/gss-serv.c openssh-9.9p1/gss-serv.c
  
  			if (gssapi_client.indicators != NULL) {
  				for (i = 0; gssapi_client.indicators[i] != NULL; i++)
-@@ -579,6 +649,24 @@
+@@ -584,6 +654,24 @@
  	return (0);
  }
  
@@ -949,7 +950,7 @@ diff -Nur openssh-9.9p1.orig/gss-serv.c openssh-9.9p1/gss-serv.c
  /* These bits are only used for rekeying. The unpriviledged child is running
   * as the user, the monitor is root.
   *
-@@ -605,9 +693,11 @@
+@@ -610,9 +698,11 @@
  	pam_handle_t *pamh = NULL;
  	struct pam_conv pamconv = {ssh_gssapi_simple_conv, NULL};
  	char *envstr;
@@ -962,7 +963,7 @@ diff -Nur openssh-9.9p1.orig/gss-serv.c openssh-9.9p1/gss-serv.c
  		return;
  
  	ok = mm_ssh_gssapi_update_creds(&gssapi_client.store);
-@@ -627,6 +717,18 @@
+@@ -632,6 +722,18 @@
  	if (ret)
  		return;
  
@@ -983,7 +984,7 @@ diff -Nur openssh-9.9p1.orig/gss-serv.c openssh-9.9p1/gss-serv.c
  
 diff -Nur openssh-9.9p1.orig/gss-serv-gsi.c openssh-9.9p1/gss-serv-gsi.c
 --- openssh-9.9p1.orig/gss-serv-gsi.c	1970-01-01 01:00:00.000000000 +0100
-+++ openssh-9.9p1/gss-serv-gsi.c	2026-03-25 09:34:38.091695448 +0100
++++ openssh-9.9p1/gss-serv-gsi.c	2026-09-22 11:12:32.505018045 +0200
 @@ -0,0 +1,328 @@
 +/*
 + * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
@@ -1314,9 +1315,9 @@ diff -Nur openssh-9.9p1.orig/gss-serv-gsi.c openssh-9.9p1/gss-serv-gsi.c
 +#endif /* GSI */
 +#endif /* GSSAPI */
 diff -Nur openssh-9.9p1.orig/gss-serv-krb5.c openssh-9.9p1/gss-serv-krb5.c
---- openssh-9.9p1.orig/gss-serv-krb5.c	2026-03-25 09:33:50.438643924 +0100
-+++ openssh-9.9p1/gss-serv-krb5.c	2026-03-25 09:34:38.111350877 +0100
-@@ -431,6 +431,34 @@
+--- openssh-9.9p1.orig/gss-serv-krb5.c	2026-09-22 11:11:59.910840837 +0200
++++ openssh-9.9p1/gss-serv-krb5.c	2026-09-22 11:12:32.505209951 +0200
+@@ -459,6 +459,34 @@
  	return found_principal;
  }
   
@@ -1351,7 +1352,7 @@ diff -Nur openssh-9.9p1.orig/gss-serv-krb5.c openssh-9.9p1/gss-serv-krb5.c
  
  /* This writes out any forwarded credentials from the structure populated
   * during userauth. Called after we have setuid to the user */
-@@ -525,7 +553,7 @@
+@@ -553,7 +581,7 @@
  	return set_env;
  }
  
@@ -1360,7 +1361,7 @@ diff -Nur openssh-9.9p1.orig/gss-serv-krb5.c openssh-9.9p1/gss-serv-krb5.c
  ssh_gssapi_krb5_updatecreds(ssh_gssapi_ccache *store,
      ssh_gssapi_client *client)
  {
-@@ -596,7 +624,7 @@
+@@ -624,7 +652,7 @@
  	{9, "\x2A\x86\x48\x86\xF7\x12\x01\x02\x02"},
  	NULL,
  	&ssh_gssapi_krb5_userok,
@@ -1370,8 +1371,8 @@ diff -Nur openssh-9.9p1.orig/gss-serv-krb5.c openssh-9.9p1/gss-serv-krb5.c
  	&ssh_gssapi_krb5_updatecreds
  };
 diff -Nur openssh-9.9p1.orig/kexgsss.c openssh-9.9p1/kexgsss.c
---- openssh-9.9p1.orig/kexgsss.c	2026-03-25 09:33:50.255131427 +0100
-+++ openssh-9.9p1/kexgsss.c	2026-03-25 09:34:38.111862186 +0100
+--- openssh-9.9p1.orig/kexgsss.c	2026-09-22 11:11:59.724068583 +0200
++++ openssh-9.9p1/kexgsss.c	2026-09-22 11:12:32.505708198 +0200
 @@ -48,6 +48,7 @@
  #include "digest.h"
  #include "ssherr.h"
@@ -1408,7 +1409,7 @@ diff -Nur openssh-9.9p1.orig/kexgsss.c openssh-9.9p1/kexgsss.c
  	}
  
  	if (!(*ret_flags & GSS_C_MUTUAL_FLAG))
-@@ -598,4 +602,26 @@
+@@ -600,4 +604,26 @@
  	return kexgssgex_final(ssh, &send_tok, &ret_flags);
  }
  
@@ -1436,8 +1437,8 @@ diff -Nur openssh-9.9p1.orig/kexgsss.c openssh-9.9p1/kexgsss.c
 +
  #endif /* defined(GSSAPI) && defined(WITH_OPENSSL) */
 diff -Nur openssh-9.9p1.orig/Makefile.in openssh-9.9p1/Makefile.in
---- openssh-9.9p1.orig/Makefile.in	2026-03-25 09:33:50.411229243 +0100
-+++ openssh-9.9p1/Makefile.in	2026-03-25 09:34:38.112504938 +0100
+--- openssh-9.9p1.orig/Makefile.in	2026-09-22 11:11:59.880188178 +0200
++++ openssh-9.9p1/Makefile.in	2026-09-22 11:12:32.506133264 +0200
 @@ -138,6 +138,7 @@
  	auth2-none.o auth2-passwd.o auth2-pubkey.o auth2-pubkeyfile.o \
  	monitor.o monitor_wrap.o auth-krb5.o kexgsss.o \
@@ -1447,8 +1448,8 @@ diff -Nur openssh-9.9p1.orig/Makefile.in openssh-9.9p1/Makefile.in
  	sftp-server.o sftp-common.o \
  	sandbox-null.o sandbox-rlimit.o sandbox-systrace.o sandbox-darwin.o \
 diff -Nur openssh-9.9p1.orig/misc.c openssh-9.9p1/misc.c
---- openssh-9.9p1.orig/misc.c	2026-03-25 09:33:50.471827794 +0100
-+++ openssh-9.9p1/misc.c	2026-03-25 09:34:38.112680450 +0100
+--- openssh-9.9p1.orig/misc.c	2026-09-22 11:11:59.985342483 +0200
++++ openssh-9.9p1/misc.c	2026-09-22 11:12:32.507145652 +0200
 @@ -440,11 +440,14 @@
  #define WHITESPACE " \t\r\n"
  #define QUOTE	"\""
@@ -1509,8 +1510,8 @@ diff -Nur openssh-9.9p1.orig/misc.c openssh-9.9p1/misc.c
   * Convert ASCII string to TCP/IP port number.
   * Port must be >=0 and <=65535.
 diff -Nur openssh-9.9p1.orig/misc.h openssh-9.9p1/misc.h
---- openssh-9.9p1.orig/misc.h	2026-03-25 09:33:50.417416573 +0100
-+++ openssh-9.9p1/misc.h	2026-03-25 09:34:38.113574002 +0100
+--- openssh-9.9p1.orig/misc.h	2026-09-22 11:11:59.887294245 +0200
++++ openssh-9.9p1/misc.h	2026-09-22 11:12:32.508664728 +0200
 @@ -112,6 +112,7 @@
  void	 sock_set_v6only(int);
  
@@ -1520,8 +1521,8 @@ diff -Nur openssh-9.9p1.orig/misc.h openssh-9.9p1/misc.h
  
  typedef void privdrop_fn(struct passwd *);
 diff -Nur openssh-9.9p1.orig/monitor.c openssh-9.9p1/monitor.c
---- openssh-9.9p1.orig/monitor.c	2026-03-25 09:33:50.472404405 +0100
-+++ openssh-9.9p1/monitor.c	2026-03-25 09:34:38.114300004 +0100
+--- openssh-9.9p1.orig/monitor.c	2026-09-22 11:11:59.985894361 +0200
++++ openssh-9.9p1/monitor.c	2026-09-22 11:12:32.508921125 +0200
 @@ -148,6 +148,9 @@
  int mm_answer_gss_userok(struct ssh *, int, struct sshbuf *);
  int mm_answer_gss_checkmic(struct ssh *, int, struct sshbuf *);
@@ -1692,8 +1693,8 @@ diff -Nur openssh-9.9p1.orig/monitor.c openssh-9.9p1/monitor.c
  {
  	gss_buffer_desc data;
 diff -Nur openssh-9.9p1.orig/monitor.h openssh-9.9p1/monitor.h
---- openssh-9.9p1.orig/monitor.h	2026-03-25 09:33:50.366536539 +0100
-+++ openssh-9.9p1/monitor.h	2026-03-25 09:34:38.115101925 +0100
+--- openssh-9.9p1.orig/monitor.h	2026-09-22 11:11:59.835960175 +0200
++++ openssh-9.9p1/monitor.h	2026-09-22 11:12:32.510720435 +0200
 @@ -75,6 +75,10 @@
  
  	MONITOR_REQ_GSSSIGN = 150, MONITOR_ANS_GSSSIGN = 151,
@@ -1706,8 +1707,8 @@ diff -Nur openssh-9.9p1.orig/monitor.h openssh-9.9p1/monitor.h
  
  struct ssh;
 diff -Nur openssh-9.9p1.orig/monitor_wrap.c openssh-9.9p1/monitor_wrap.c
---- openssh-9.9p1.orig/monitor_wrap.c	2026-03-25 09:33:50.372322000 +0100
-+++ openssh-9.9p1/monitor_wrap.c	2026-03-25 09:34:38.115448828 +0100
+--- openssh-9.9p1.orig/monitor_wrap.c	2026-09-22 11:11:59.842260271 +0200
++++ openssh-9.9p1/monitor_wrap.c	2026-09-22 11:12:32.510921124 +0200
 @@ -1139,6 +1139,94 @@
  	return (authenticated);
  }
@@ -1804,8 +1805,8 @@ diff -Nur openssh-9.9p1.orig/monitor_wrap.c openssh-9.9p1/monitor_wrap.c
  mm_ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *data, gss_buffer_desc *hash)
  {
 diff -Nur openssh-9.9p1.orig/monitor_wrap.h openssh-9.9p1/monitor_wrap.h
---- openssh-9.9p1.orig/monitor_wrap.h	2026-03-25 09:33:50.374854035 +0100
-+++ openssh-9.9p1/monitor_wrap.h	2026-03-25 09:34:38.115832467 +0100
+--- openssh-9.9p1.orig/monitor_wrap.h	2026-09-22 11:11:59.842639260 +0200
++++ openssh-9.9p1/monitor_wrap.h	2026-09-22 11:12:32.511921124 +0200
 @@ -72,6 +72,10 @@
  int mm_ssh_gssapi_userok(char *user, struct passwd *, int kex);
  OM_uint32 mm_ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t);
@@ -1818,9 +1819,9 @@ diff -Nur openssh-9.9p1.orig/monitor_wrap.h openssh-9.9p1/monitor_wrap.h
  #endif
  
 diff -Nur openssh-9.9p1.orig/readconf.c openssh-9.9p1/readconf.c
---- openssh-9.9p1.orig/readconf.c	2026-03-25 09:33:50.473798512 +0100
-+++ openssh-9.9p1/readconf.c	2026-03-25 09:34:38.116680413 +0100
-@@ -2812,11 +2812,11 @@
+--- openssh-9.9p1.orig/readconf.c	2026-09-22 11:11:59.987164427 +0200
++++ openssh-9.9p1/readconf.c	2026-09-22 11:12:32.513050248 +0200
+@@ -2810,11 +2810,11 @@
  	if (options->pubkey_authentication == -1)
  		options->pubkey_authentication = SSH_PUBKEY_AUTH_ALL;
  	if (options->gss_authentication == -1)
@@ -1836,8 +1837,8 @@ diff -Nur openssh-9.9p1.orig/readconf.c openssh-9.9p1/readconf.c
  		options->gss_trust_dns = 0;
  	if (options->gss_renewal_rekey == -1)
 diff -Nur openssh-9.9p1.orig/readconf.h openssh-9.9p1/readconf.h
---- openssh-9.9p1.orig/readconf.h	2026-03-25 09:33:50.259743691 +0100
-+++ openssh-9.9p1/readconf.h	2026-03-25 09:34:38.117292644 +0100
+--- openssh-9.9p1.orig/readconf.h	2026-09-22 11:11:59.960094972 +0200
++++ openssh-9.9p1/readconf.h	2026-09-22 11:12:32.513985509 +0200
 @@ -80,6 +80,8 @@
  	char   *host_key_alias;	/* hostname alias for .ssh/known_hosts */
  	char   *proxy_command;	/* Proxy command for connecting the host. */
@@ -1848,8 +1849,8 @@ diff -Nur openssh-9.9p1.orig/readconf.h openssh-9.9p1/readconf.h
  
  	u_int	num_system_hostfiles;	/* Paths for /etc/ssh/ssh_known_hosts */
 diff -Nur openssh-9.9p1.orig/servconf.c openssh-9.9p1/servconf.c
---- openssh-9.9p1.orig/servconf.c	2026-03-25 09:33:50.474757506 +0100
-+++ openssh-9.9p1/servconf.c	2026-03-25 10:25:51.442170347 +0100
+--- openssh-9.9p1.orig/servconf.c	2026-09-22 11:11:59.987925574 +0200
++++ openssh-9.9p1/servconf.c	2026-09-22 11:12:32.514843394 +0200
 @@ -95,6 +95,7 @@
  	/* Portable-specific options */
  	options->use_pam = -1;
@@ -1895,7 +1896,7 @@ diff -Nur openssh-9.9p1.orig/servconf.c openssh-9.9p1/servconf.c
  	if (options->gss_store_rekey == -1)
  		options->gss_store_rekey = 0;
  #ifdef GSSAPI
-@@ -580,7 +586,7 @@
+@@ -581,7 +587,7 @@
  typedef enum {
  	sBadOption,		/* == unknown option */
  	/* Portable-specific options */
@@ -1904,7 +1905,7 @@ diff -Nur openssh-9.9p1.orig/servconf.c openssh-9.9p1/servconf.c
  	/* Standard Options */
  	sPort, sHostKeyFile, sLoginGraceTime,
  	sPermitRootLogin, sLogFacility, sLogLevel, sLogVerbose,
-@@ -602,6 +608,8 @@
+@@ -603,6 +609,8 @@
  	sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile,
  	sGssAuthentication, sGssCleanupCreds, sGssDelegateCreds,
  	sGssEnablek5users, sGssStrictAcceptor,
@@ -1913,7 +1914,7 @@ diff -Nur openssh-9.9p1.orig/servconf.c openssh-9.9p1/servconf.c
  	sGssKeyEx, sGssIndicators, sGssKexAlgorithms, sGssStoreRekey,
  	sAcceptEnv, sSetEnv, sPermitTunnel,
  	sMatch, sPermitOpen, sPermitListen, sForceCommand, sChrootDirectory,
-@@ -636,9 +644,11 @@
+@@ -637,9 +645,11 @@
  #ifdef USE_PAM
  	{ "usepam", sUsePAM, SSHCFG_GLOBAL },
  	{ "pamservicename", sPAMServiceName, SSHCFG_ALL },
@@ -1925,7 +1926,7 @@ diff -Nur openssh-9.9p1.orig/servconf.c openssh-9.9p1/servconf.c
  #endif
  	{ "pamauthenticationviakbdint", sDeprecated, SSHCFG_GLOBAL },
  	/* Standard Options */
-@@ -694,6 +704,12 @@
+@@ -695,6 +705,12 @@
  	{ "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL },
  	{ "gssapicleanupcreds", sGssCleanupCreds, SSHCFG_GLOBAL },
  	{ "gssapidelegatecredentials", sGssDelegateCreds, SSHCFG_GLOBAL },
@@ -1938,7 +1939,7 @@ diff -Nur openssh-9.9p1.orig/servconf.c openssh-9.9p1/servconf.c
  	{ "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL },
  	{ "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL },
  	{ "gssapistorecredentialsonrekey", sGssStoreRekey, SSHCFG_GLOBAL },
-@@ -705,6 +721,8 @@
+@@ -706,6 +722,8 @@
  	{ "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL },
  	{ "gssapicleanupcreds", sUnsupported, SSHCFG_GLOBAL },
  	{ "gssapidelegatecredentials", sUnsupported, SSHCFG_GLOBAL },
@@ -1947,7 +1948,7 @@ diff -Nur openssh-9.9p1.orig/servconf.c openssh-9.9p1/servconf.c
  	{ "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL },
  	{ "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL },
  	{ "gssapistorecredentialsonrekey", sUnsupported, SSHCFG_GLOBAL },
-@@ -779,6 +797,8 @@
+@@ -780,6 +798,8 @@
  	{ "permitlisten", sPermitListen, SSHCFG_ALL },
  	{ "forcecommand", sForceCommand, SSHCFG_ALL },
  	{ "chrootdirectory", sChrootDirectory, SSHCFG_ALL },
@@ -1956,7 +1957,7 @@ diff -Nur openssh-9.9p1.orig/servconf.c openssh-9.9p1/servconf.c
  	{ "hostcertificate", sHostCertificate, SSHCFG_GLOBAL },
  	{ "revokedkeys", sRevokedKeys, SSHCFG_ALL },
  	{ "trustedusercakeys", sTrustedUserCAKeys, SSHCFG_ALL },
-@@ -1449,6 +1469,10 @@
+@@ -1451,6 +1471,10 @@
  			*charptr = xstrdup(arg);
  		break;
  
@@ -1967,7 +1968,7 @@ diff -Nur openssh-9.9p1.orig/servconf.c openssh-9.9p1/servconf.c
  	/* Standard Options */
  	case sBadOption:
  		goto out;
-@@ -1712,6 +1736,10 @@
+@@ -1714,6 +1738,10 @@
  		intptr = &options->gss_deleg_creds;
  		goto parse_flag;
  
@@ -1978,7 +1979,7 @@ diff -Nur openssh-9.9p1.orig/servconf.c openssh-9.9p1/servconf.c
  	case sGssStrictAcceptor:
  		intptr = &options->gss_strict_acceptor;
  		goto parse_flag;
-@@ -1741,6 +1769,12 @@
+@@ -1743,6 +1771,12 @@
  			options->gss_indicators = xstrdup(arg);
  		break;
  
@@ -1991,7 +1992,7 @@ diff -Nur openssh-9.9p1.orig/servconf.c openssh-9.9p1/servconf.c
  	case sPasswordAuthentication:
  		intptr = &options->password_authentication;
  		goto parse_flag;
-@@ -3010,6 +3044,7 @@
+@@ -3014,6 +3048,7 @@
  
  	M_CP_INTOPT(password_authentication);
  	M_CP_INTOPT(gss_authentication);
@@ -2000,8 +2001,8 @@ diff -Nur openssh-9.9p1.orig/servconf.c openssh-9.9p1/servconf.c
  	M_CP_INTOPT(pubkey_auth_options);
  	M_CP_INTOPT(kerberos_authentication);
 diff -Nur openssh-9.9p1.orig/servconf.h openssh-9.9p1/servconf.h
---- openssh-9.9p1.orig/servconf.h	2026-03-25 09:33:50.464980881 +0100
-+++ openssh-9.9p1/servconf.h	2026-03-25 09:46:47.987930866 +0100
+--- openssh-9.9p1.orig/servconf.h	2026-09-22 11:11:59.936404684 +0200
++++ openssh-9.9p1/servconf.h	2026-09-22 11:12:32.515626582 +0200
 @@ -155,10 +155,12 @@
  						 * be stored in per-session ccache */
  	int	use_kuserok;
@@ -2024,8 +2025,8 @@ diff -Nur openssh-9.9p1.orig/servconf.h openssh-9.9p1/servconf.h
  	int	permit_tun;
  
 diff -Nur openssh-9.9p1.orig/ssh.1 openssh-9.9p1/ssh.1
---- openssh-9.9p1.orig/ssh.1	2026-03-25 09:33:50.389637598 +0100
-+++ openssh-9.9p1/ssh.1	2026-03-25 09:34:38.120502979 +0100
+--- openssh-9.9p1.orig/ssh.1	2026-09-22 11:11:59.857734886 +0200
++++ openssh-9.9p1/ssh.1	2026-09-22 11:12:32.516173126 +0200
 @@ -1523,6 +1523,18 @@
  on to new connections).
  .It Ev USER
@@ -2046,8 +2047,8 @@ diff -Nur openssh-9.9p1.orig/ssh.1 openssh-9.9p1/ssh.1
  .Pp
  Additionally,
 diff -Nur openssh-9.9p1.orig/ssh.c openssh-9.9p1/ssh.c
---- openssh-9.9p1.orig/ssh.c	2026-03-25 09:33:50.460316864 +0100
-+++ openssh-9.9p1/ssh.c	2026-03-25 09:34:38.120680376 +0100
+--- openssh-9.9p1.orig/ssh.c	2026-09-22 11:11:59.978010980 +0200
++++ openssh-9.9p1/ssh.c	2026-09-22 11:12:32.517284751 +0200
 @@ -585,6 +585,38 @@
  			fatal("Can't open user config file %.100s: "
  			    "%.100s", config, strerror(errno));
@@ -2087,7 +2088,7 @@ diff -Nur openssh-9.9p1.orig/ssh.c openssh-9.9p1/ssh.c
  		r = snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir,
  		    _PATH_SSH_USER_CONFFILE);
  		if (r > 0 && (size_t)r < sizeof(buf))
-@@ -1318,8 +1350,12 @@
+@@ -1266,8 +1298,12 @@
  	if (fill_default_options(&options) != 0)
  		cleanup_exit(255);
  
@@ -2102,8 +2103,8 @@ diff -Nur openssh-9.9p1.orig/ssh.c openssh-9.9p1/ssh.c
  	/*
  	 * If ProxyJump option specified, then construct a ProxyCommand now.
 diff -Nur openssh-9.9p1.orig/ssh_config openssh-9.9p1/ssh_config
---- openssh-9.9p1.orig/ssh_config	2026-03-25 09:33:50.262532812 +0100
-+++ openssh-9.9p1/ssh_config	2026-03-25 09:34:38.121528811 +0100
+--- openssh-9.9p1.orig/ssh_config	2026-09-22 11:11:59.730208494 +0200
++++ openssh-9.9p1/ssh_config	2026-09-22 11:12:32.517828512 +0200
 @@ -22,9 +22,9 @@
  #   ForwardX11 no
  #   PasswordAuthentication yes
@@ -2118,8 +2119,8 @@ diff -Nur openssh-9.9p1.orig/ssh_config openssh-9.9p1/ssh_config
  #   BatchMode no
  #   CheckHostIP no
 diff -Nur openssh-9.9p1.orig/ssh_config.5 openssh-9.9p1/ssh_config.5
---- openssh-9.9p1.orig/ssh_config.5	2026-03-25 09:33:50.405557553 +0100
-+++ openssh-9.9p1/ssh_config.5	2026-03-25 09:34:38.122152007 +0100
+--- openssh-9.9p1.orig/ssh_config.5	2026-09-22 11:11:59.873925590 +0200
++++ openssh-9.9p1/ssh_config.5	2026-09-22 11:12:32.518246391 +0200
 @@ -52,6 +52,12 @@
  user's configuration file
  .Pq Pa ~/.ssh/config
@@ -2167,9 +2168,9 @@ diff -Nur openssh-9.9p1.orig/ssh_config.5 openssh-9.9p1/ssh_config.5
  .Ed
  .It Cm ProxyCommand
 diff -Nur openssh-9.9p1.orig/sshconnect2.c openssh-9.9p1/sshconnect2.c
---- openssh-9.9p1.orig/sshconnect2.c	2026-03-25 09:33:50.456077275 +0100
-+++ openssh-9.9p1/sshconnect2.c	2026-03-25 09:34:38.122746009 +0100
-@@ -860,6 +860,11 @@
+--- openssh-9.9p1.orig/sshconnect2.c	2026-09-22 11:11:59.965745669 +0200
++++ openssh-9.9p1/sshconnect2.c	2026-09-22 11:12:32.519597227 +0200
+@@ -867,6 +867,11 @@
  	gss_OID mech = NULL;
  	char *gss_host = NULL;
  
@@ -2181,7 +2182,7 @@ diff -Nur openssh-9.9p1.orig/sshconnect2.c openssh-9.9p1/sshconnect2.c
  	if (options.gss_server_identity) {
  		gss_host = xstrdup(options.gss_server_identity);
  	} else if (options.gss_trust_dns) {
-@@ -968,7 +973,8 @@
+@@ -975,7 +980,8 @@
  
  	if (status == GSS_S_COMPLETE) {
  		/* send either complete or MIC, depending on mechanism */
@@ -2191,7 +2192,7 @@ diff -Nur openssh-9.9p1.orig/sshconnect2.c openssh-9.9p1/sshconnect2.c
  			if ((r = sshpkt_start(ssh,
  			    SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE)) != 0 ||
  			    (r = sshpkt_send(ssh)) != 0)
-@@ -1135,6 +1141,20 @@
+@@ -1142,6 +1148,20 @@
  	return r;
  }
  
@@ -2212,7 +2213,7 @@ diff -Nur openssh-9.9p1.orig/sshconnect2.c openssh-9.9p1/sshconnect2.c
  int
  userauth_gsskeyex(struct ssh *ssh)
  {
-@@ -1157,6 +1177,12 @@
+@@ -1164,6 +1184,12 @@
  	if ((b = sshbuf_new()) == NULL)
  		fatal_f("sshbuf_new failed");
  
@@ -2225,7 +2226,7 @@ diff -Nur openssh-9.9p1.orig/sshconnect2.c openssh-9.9p1/sshconnect2.c
  	ssh_gssapi_buildmic(b, authctxt->server_user, authctxt->service,
  	    "gssapi-keyex", ssh->kex->session_id);
  
-@@ -1170,7 +1196,9 @@
+@@ -1177,7 +1203,9 @@
  	}
  
  	if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_REQUEST)) != 0 ||
@@ -2237,8 +2238,8 @@ diff -Nur openssh-9.9p1.orig/sshconnect2.c openssh-9.9p1/sshconnect2.c
  	    (r = sshpkt_put_cstring(ssh, authctxt->method->name)) != 0 ||
  	    (r = sshpkt_put_string(ssh, mic.value, mic.length)) != 0 ||
 diff -Nur openssh-9.9p1.orig/sshd.8 openssh-9.9p1/sshd.8
---- openssh-9.9p1.orig/sshd.8	2026-03-25 09:33:50.278816152 +0100
-+++ openssh-9.9p1/sshd.8	2026-03-25 09:34:38.123594583 +0100
+--- openssh-9.9p1.orig/sshd.8	2026-09-22 11:11:59.745058855 +0200
++++ openssh-9.9p1/sshd.8	2026-09-22 11:12:32.520228070 +0200
 @@ -840,6 +840,29 @@
  # A CA key, accepted for any host in *.mydomain.com or *.mydomain.org
  @cert-authority *.mydomain.org,*.mydomain.com ssh-rsa AAAAB5W...
@@ -2270,8 +2271,8 @@ diff -Nur openssh-9.9p1.orig/sshd.8 openssh-9.9p1/sshd.8
  .Bl -tag -width Ds -compact
  .It Pa ~/.hushlogin
 diff -Nur openssh-9.9p1.orig/sshd_config openssh-9.9p1/sshd_config
---- openssh-9.9p1.orig/sshd_config	2026-03-25 09:33:50.303016028 +0100
-+++ openssh-9.9p1/sshd_config	2026-03-25 09:34:38.124023480 +0100
+--- openssh-9.9p1.orig/sshd_config	2026-09-22 11:11:59.767232271 +0200
++++ openssh-9.9p1/sshd_config	2026-09-22 11:12:32.520966150 +0200
 @@ -76,10 +76,11 @@
  #KerberosUseKuserok yes
  
@@ -2298,8 +2299,8 @@ diff -Nur openssh-9.9p1.orig/sshd_config openssh-9.9p1/sshd_config
  #AllowTcpForwarding yes
  #GatewayPorts no
 diff -Nur openssh-9.9p1.orig/sshd_config.5 openssh-9.9p1/sshd_config.5
---- openssh-9.9p1.orig/sshd_config.5	2026-03-25 09:33:50.465574045 +0100
-+++ openssh-9.9p1/sshd_config.5	2026-03-25 09:56:30.278555815 +0100
+--- openssh-9.9p1.orig/sshd_config.5	2026-09-22 11:11:59.937230921 +0200
++++ openssh-9.9p1/sshd_config.5	2026-09-22 11:12:32.521439640 +0200
 @@ -724,15 +724,30 @@
  to allow the client to select the address to which the forwarding is bound.
  The default is
@@ -2331,7 +2332,7 @@ diff -Nur openssh-9.9p1.orig/sshd_config.5 openssh-9.9p1/sshd_config.5
 +Currently only implemented for the GSI mechanism.
  .It Cm GSSAPIDelegateCredentials
  Accept delegated credentials on the server side.  The default is
- .CM yes .
+ .Cm yes .
 @@ -746,7 +761,7 @@
  Specifies whether key exchange based on GSSAPI is allowed. GSSAPI key exchange
  doesn't rely on ssh keys to verify host identity.
@@ -2341,7 +2342,7 @@ diff -Nur openssh-9.9p1.orig/sshd_config.5 openssh-9.9p1/sshd_config.5
  .It Cm GSSAPIStrictAcceptorCheck
  Determines whether to be strict about the identity of the GSSAPI acceptor
  a client authenticates against.
-@@ -2096,6 +2111,12 @@
+@@ -2098,6 +2113,12 @@
  as a non-root user.
  The default is
  .Cm no .
@@ -2355,8 +2356,8 @@ diff -Nur openssh-9.9p1.orig/sshd_config.5 openssh-9.9p1/sshd_config.5
  Optionally specifies additional text to append to the SSH protocol banner
  sent by the server upon connection.
 diff -Nur openssh-9.9p1.orig/sshd_config_redhat openssh-9.9p1/sshd_config_redhat
---- openssh-9.9p1.orig/sshd_config_redhat	2026-03-25 09:33:50.242937866 +0100
-+++ openssh-9.9p1/sshd_config_redhat	2026-03-25 09:34:38.125435117 +0100
+--- openssh-9.9p1.orig/sshd_config_redhat	2026-09-22 11:11:59.713996868 +0200
++++ openssh-9.9p1/sshd_config_redhat	2026-09-22 11:12:32.521959472 +0200
 @@ -2,9 +2,6 @@
  
  ChallengeResponseAuthentication no
@@ -2368,8 +2369,8 @@ diff -Nur openssh-9.9p1.orig/sshd_config_redhat openssh-9.9p1/sshd_config_redhat
  
  X11Forwarding yes
 diff -Nur openssh-9.9p1.orig/sshd-session.c openssh-9.9p1/sshd-session.c
---- openssh-9.9p1.orig/sshd-session.c	2026-03-25 09:33:50.476356457 +0100
-+++ openssh-9.9p1/sshd-session.c	2026-03-25 09:34:38.126169151 +0100
+--- openssh-9.9p1.orig/sshd-session.c	2026-09-22 11:11:59.989485280 +0200
++++ openssh-9.9p1/sshd-session.c	2026-09-22 11:12:32.522274647 +0200
 @@ -1486,7 +1486,7 @@
  #endif
  
@@ -2380,8 +2381,8 @@ diff -Nur openssh-9.9p1.orig/sshd-session.c openssh-9.9p1/sshd-session.c
  		authctxt->krb5_set_env = ssh_gssapi_storecreds();
  		restore_uid();
 diff -Nur openssh-9.9p1.orig/ssh-gss.h openssh-9.9p1/ssh-gss.h
---- openssh-9.9p1.orig/ssh-gss.h	2026-03-25 09:33:50.440761798 +0100
-+++ openssh-9.9p1/ssh-gss.h	2026-03-25 09:34:38.126851573 +0100
+--- openssh-9.9p1.orig/ssh-gss.h	2026-09-22 11:11:59.912508776 +0200
++++ openssh-9.9p1/ssh-gss.h	2026-09-22 11:12:32.523171631 +0200
 @@ -110,12 +110,14 @@
  } ssh_gssapi_ccache;
  
@@ -2419,7 +2420,7 @@ diff -Nur openssh-9.9p1.orig/ssh-gss.h openssh-9.9p1/ssh-gss.h
      const char *);
 diff -Nur openssh-9.9p1.orig/version.h openssh-9.9p1/version.h
 --- openssh-9.9p1.orig/version.h	2024-09-20 00:20:48.000000000 +0200
-+++ openssh-9.9p1/version.h	2026-03-25 09:34:38.127196380 +0100
++++ openssh-9.9p1/version.h	2026-09-22 11:12:32.523669865 +0200
 @@ -2,5 +2,19 @@
  
  #define SSH_VERSION	"OpenSSH_9.9"

diff --git a/openssh-9.9p1-scp-remote-glob.patch b/openssh-9.9p1-scp-remote-glob.patch
new file mode 100644
index 0000000..c08101e
--- /dev/null
+++ b/openssh-9.9p1-scp-remote-glob.patch
@@ -0,0 +1,14 @@
+diff --color -ruNp a/scp.c b/scp.c
+--- a/scp.c	2026-07-14 11:40:47.754600847 +0200
++++ b/scp.c	2026-07-14 11:43:04.077524517 +0200
+@@ -2070,6 +2070,10 @@ throughlocal_sftp(struct sftp_conn *from
+ 			goto out;
+ 		}
+ 
++		/* Special handling for source of '..' */
++		if (strcmp(filename, "..") == 0)
++			filename = "."; /* Download to dest, not dest/.. */
++
+ 		if (targetisdir)
+ 			abs_dst = sftp_path_append(target, filename);
+ 		else

diff --git a/openssh-9.9p1-sshd-no-delegate-credentials.patch b/openssh-9.9p1-sshd-no-delegate-credentials.patch
index 59d0120..7132c9b 100644
--- a/openssh-9.9p1-sshd-no-delegate-credentials.patch
+++ b/openssh-9.9p1-sshd-no-delegate-credentials.patch
@@ -111,7 +111,7 @@ diff --color -ruNp a/sshd_config.5 b/sshd_config.5
  .Cm yes .
 +.It Cm GSSAPIDelegateCredentials
 +Accept delegated credentials on the server side.  The default is
-+.CM yes .
++.Cm yes .
  .It Cm GSSAPIEnablek5users
  Specifies whether to look at .k5users file for GSSAPI authentication
  access control. Further details are described in

diff --git a/openssh-9.9p1-support-authentication-indicators-in-GSSAPI.patch b/openssh-9.9p1-support-authentication-indicators-in-GSSAPI.patch
index 6c55a66..ef70379 100644
--- a/openssh-9.9p1-support-authentication-indicators-in-GSSAPI.patch
+++ b/openssh-9.9p1-support-authentication-indicators-in-GSSAPI.patch
@@ -10,8 +10,8 @@ diff --color -ruNp a/configure.ac b/configure.ac
  		AC_SEARCH_LIBS([k_hasafs], [kafs], [AC_DEFINE([USE_AFS], [1],
  			[Define this if you want to use libkafs' AFS support])])
 diff --color -ruNp a/gss-serv.c b/gss-serv.c
---- a/gss-serv.c	2026-03-10 12:43:36.802443034 +0100
-+++ b/gss-serv.c	2026-03-12 10:04:37.520993330 +0100
+--- a/gss-serv.c	2026-06-16 15:38:26.590728235 +0200
++++ b/gss-serv.c	2026-06-16 15:41:13.717696103 +0200
 @@ -53,7 +53,7 @@ extern ServerOptions options;
  
  static ssh_gssapi_client gssapi_client =
@@ -21,7 +21,7 @@ diff --color -ruNp a/gss-serv.c b/gss-serv.c
  
  ssh_gssapi_mech gssapi_null_mech =
      { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL, NULL};
-@@ -295,6 +295,95 @@ ssh_gssapi_parse_ename(Gssctxt *ctx, gss
+@@ -295,6 +295,99 @@ ssh_gssapi_parse_ename(Gssctxt *ctx, gss
  	return GSS_S_COMPLETE;
  }
  
@@ -44,63 +44,67 @@ diff --color -ruNp a/gss-serv.c b/gss-serv.c
 +	int is_mechname, authenticated, complete, more;
 +	size_t count, i;
 +
++	/* always initialize client->indicators */
++	client->indicators = NULL;
++
 +	ctx->major = gss_inquire_name(&ctx->minor, gss_name,
 +				      &is_mechname, NULL, &attrs);
-+	if (ctx->major != GSS_S_COMPLETE) {
-+		return (ctx->major);
-+	}
++	if (ctx->major != GSS_S_COMPLETE)
++		return ctx->major;
 +
 +	if (attrs == GSS_C_NO_BUFFER_SET) {
-+		/* No indicators in the ticket */
-+		return (0);
++		/* no indicators in the ticket */
++		return GSS_S_COMPLETE;
 +	}
 +
-+	client->indicators = NULL;
++	/* client->indicators is NULL terminated */
 +	count = 0;
++	client->indicators = xcalloc(count + 1, sizeof(char *));
++
 +	for (i = 0; i < attrs->count; i++) {
 +		authenticated = 0;
 +		complete = 0;
 +		more = -1;
++
 +		/* skip anything but auth-indicators */
 +		if (((sizeof(AUTH_INDICATORS_TAG) - 1) != attrs->elements[i].length) ||
-+		    memcmp(AUTH_INDICATORS_TAG,
-+			   attrs->elements[i].value,
++		    memcmp(AUTH_INDICATORS_TAG, attrs->elements[i].value,
 +			   sizeof(AUTH_INDICATORS_TAG) - 1) != 0)
 +			continue;
++
 +		/* retrieve all indicators */
 +		while (more != 0) {
 +			value.value = NULL;
 +			display_value.value = NULL;
++
 +			ctx->major = gss_get_name_attribute(&ctx->minor, gss_name,
-+							    &attrs->elements[i], &authenticated,
-+							    &complete, &value, &display_value, &more);
++							    &attrs->elements[i],
++							    &authenticated, &complete,
++							    &value, &display_value, &more);
 +			if (ctx->major != GSS_S_COMPLETE)
 +				goto out;
 +
-+			if ((value.value != NULL) && authenticated) {
-+				if (count >= SSH_GSSAPI_MAX_INDICATORS) {
-+					logit("ssh_gssapi_getindicators: too many "
-+					    "indicators, truncating at %d",
-+					    SSH_GSSAPI_MAX_INDICATORS);
-+					/* value/display_value released at out: */
-+					goto done;
-+				}
++			if (value.value == NULL || !authenticated)
++				continue;
 +
-+				client->indicators = xrecallocarray(client->indicators, count, count + 1, sizeof(char*));
-+				if (client->indicators == NULL) {
-+					fatal("ssh_gssapi_getindicators failed to allocate memory");
-+				}
-+				client->indicators[count] = xmalloc(value.length + 1);
-+				memcpy(client->indicators[count], value.value, value.length);
-+				client->indicators[count][value.length] = '\0';
-+				count++;
++			if (count >= SSH_GSSAPI_MAX_INDICATORS) {
++				logit("ssh_gssapi_getindicators:"
++				      " too many indicators, truncating at %d",
++				      SSH_GSSAPI_MAX_INDICATORS);
++				goto out;
 +			}
++
++			client->indicators[count] = xmalloc(value.length + 1);
++			memcpy(client->indicators[count], value.value, value.length);
++			client->indicators[count][value.length] = '\0';
++			count++;
++
++			/* add NULL terminator */
++			client->indicators = xrecallocarray(client->indicators, count,
++							    count + 1, sizeof(char *));
 +		}
 +	}
 +
-+done:
-+	/* slot [count] is zeroed by recallocarray, serves as NULL sentinel */
-+
 +out:
 +	if (ctx->major != GSS_S_COMPLETE && client->indicators != NULL) {
 +		for (i = 0; i < count; i++)
@@ -108,16 +112,16 @@ diff --color -ruNp a/gss-serv.c b/gss-serv.c
 +		free(client->indicators);
 +		client->indicators = NULL;
 +	}
-+	(void) gss_release_buffer(&ctx->minor, &value);
-+	(void) gss_release_buffer(&ctx->minor, &display_value);
-+	(void) gss_release_buffer_set(&ctx->minor, &attrs);
-+	return (ctx->major);
++	gss_release_buffer(&ctx->minor, &value);
++	gss_release_buffer(&ctx->minor, &display_value);
++	gss_release_buffer_set(&ctx->minor, &attrs);
++	return ctx->major;
 +}
 +
  /* Extract the client details from a given context. This can only reliably
   * be called once for a context */
  
-@@ -384,6 +473,12 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_g
+@@ -384,6 +477,12 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_g
  	}
  
  	gss_release_buffer(&ctx->minor, &ename);
@@ -130,7 +134,7 @@ diff --color -ruNp a/gss-serv.c b/gss-serv.c
  
  	/* We can't copy this structure, so we just move the pointer to it */
  	client->creds = ctx->client_creds;
-@@ -446,6 +541,7 @@ int
+@@ -446,6 +545,7 @@ int
  ssh_gssapi_userok(char *user, struct passwd *pw, int kex)
  {
  	OM_uint32 lmin;
@@ -138,7 +142,7 @@ diff --color -ruNp a/gss-serv.c b/gss-serv.c
  
  	(void) kex; /* used in privilege separation */
  
-@@ -464,8 +560,14 @@ ssh_gssapi_userok(char *user, struct pas
+@@ -464,8 +564,14 @@ ssh_gssapi_userok(char *user, struct pas
  			gss_release_buffer(&lmin, &gssapi_client.displayname);
  			gss_release_buffer(&lmin, &gssapi_client.exportedname);
  			gss_release_cred(&lmin, &gssapi_client.creds);
@@ -166,7 +170,7 @@ diff --color -ruNp a/gss-serv-krb5.c b/gss-serv-krb5.c
  
  #include "ssh-gss.h"
  
-@@ -87,6 +88,33 @@ ssh_gssapi_krb5_init(void)
+@@ -87,6 +88,42 @@ ssh_gssapi_krb5_init(void)
  	return 1;
  }
  
@@ -174,6 +178,10 @@ diff --color -ruNp a/gss-serv-krb5.c b/gss-serv-krb5.c
 + * one of indicators in the list of allowed/denied rules.
 + * In case of the match, apply the decision from the rule.
 + * In case of no indicator from the ticket matching the rule, deny
++ *
++ * Returns -1 on any negative match
++ * Returns 1 on positive match and no negative matches
++ * Returns 0 when no matches occurred
 + */
 +
 +static int
@@ -183,18 +191,23 @@ diff --color -ruNp a/gss-serv-krb5.c b/gss-serv-krb5.c
 +	u_int i;
 +	*matched = -1;
 +
-+	/* Check indicators */
 +	for (i = 0; client->indicators[i] != NULL; i++) {
 +		ret = match_pattern_list(client->indicators[i],
 +					 options.gss_indicators, 1);
-+		/* negative or positive match */
-+		if (ret != 0) {
++
++		/* record first positive match */
++		if (ret == 1 && *matched == -1)
++			*matched = i;
++
++		/* deny rule matched, return negative */
++		if (ret == -1) {
 +			*matched = i;
-+			return ret;
++			return -1;
 +		}
 +	}
-+	/* No rule matched */
-+	return 0;
++	/* if there was a match, it was positive,
++	 * otherwise no match */
++	return *matched != -1;
 +}
 +
  /* Check if this user is OK to login. This only works with krb5 - other

                 reply	other threads:[~2026-09-22 19:59 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=179010718716.1.8971071598837401023.rpms-gsi-openssh-c69d9b538f65@fedoraproject.org \
    --to=mattias.ellert@physics.uu.se \
    --cc=git-commits@fedoraproject.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox