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-26.el10
Date: Sat, 30 May 2026 01:18:33 GMT	[thread overview]
Message-ID: <178010391315.1.15221795594920214601.rpms-gsi-openssh-52f242b91bc2@fedoraproject.org> (raw)

A new commit has been pushed.

Repo   : rpms/gsi-openssh
Branch : epel10
Commit : 52f242b91bc224468ae1b43e61723343aace3881
Author : Mattias Ellert <mattias.ellert@physics.uu.se>
Date   : 2026-05-30T03:09:06+02:00
Stats  : +1518/-423 in 18 file(s)
URL    : https://src.fedoraproject.org/rpms/gsi-openssh/c/52f242b91bc224468ae1b43e61723343aace3881?branch=epel10

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

---
diff --git a/gsi-openssh.spec b/gsi-openssh.spec
index 1481a42..b80cf40 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: 5%{?dist}
+Release: 6%{?dist}
 Provides: gsissh = %{version}-%{release}
 Obsoletes: gsissh < 5.8p2-2
 URL: http://www.openssh.com/portable.html
@@ -207,6 +207,30 @@ Patch1032: openssh-9.9p1-reject-cntrl-chars-in-username.patch
 Patch1033: openssh-9.9p1-reject-null-char-in-url-string.patch
 Patch1034: openssh-9.9p1-sshd-no-delegate-credentials.patch
 Patch1035: openssh-10.0-mlkem-nist-fips.patch
+# upstream 683d0abe596b069a896f1688f86256f1beeb0cdc
+# upstream 9313233a735733821dfd170b70782fb7da492962
+# upstream 2b0f4a72bd87bef7cc9f0a1889cfc98545cbb158
+# upstream 19f7cb39eecb4b8f768f37e8294dc3a9142e022b
+# upstream 97b32fa2af25c16aec4de85c5cbb63fd038b4dfa
+Patch1037: openssh-9.9p1-first-match-wins.patch
+# upstream eddd1d2daa64a6ab1a915ca88436fa41aede44d4
+# upstream bc328144f149af07139a0f2c1329018cd85b86b7
+Patch1038: openssh-9.9p1-maxstartups-mistracking.patch
+# https://github.com/openssh/openssh-portable/pull/649
+Patch1039: openssh-9.9p1-fill-default-options-error.patch
+# upstream 487e8ac146f7d6616f65c125d5edb210519b833a
+Patch1040: openssh-9.9p1-scp-clear-setuid.patch
+# upstream c805b97b67c774e0bf922ffb29dfbcda9d7b5add
+Patch1041: openssh-9.9p1-mux-askpass-check.patch
+# upstream fd1c7e131f331942d20f42f31e79912d570081fa
+Patch1042: openssh-9.9p1-ecdsa-incomplete-application.patch
+# upstream fd1c7e131f331942d20f42f31e79912d570081fa
+Patch1043: openssh-9.9p1-authorized-keys-principles-option.patch
+# upstream 76685c9b09a66435cd2ad8373246adf1c53976d3
+# upstream 0a0ef4515361143cad21afa072319823854c1cf6
+# upstream 607bd871ec029e9aa22e632a22547250f3cae223
+# upstream 1340d3fa8e4bb122906a82159c4c9b91584d65ce
+Patch1044: openssh-9.9p1-proxyjump-username-validity-checks.patch
 
 # This is the patch that adds GSI support
 # Based on hpn_isshd-gsi.7.5p1b.patch from Globus upstream
@@ -216,7 +240,7 @@ Patch98: openssh-9.9p1-gsissh.patch
 # Based on https://github.com/rapier1/hpn-ssh/ tag: hpn-18.6.0
 Patch99: openssh-9.9p1-hpn-18.6.0.patch
 
-License: BSD-3-Clause AND BSD-2-Clause AND ISC AND SSH-OpenSSH AND ssh-keyscan AND sprintf AND LicenseRef-Fedora-Public-Domain AND X11-distribute-modifications-variant
+License: BSD-3-Clause AND BSD-2-Clause AND ISC AND SSH-OpenSSH AND ssh-keyscan AND snprintf AND LicenseRef-Fedora-Public-Domain AND X11-distribute-modifications-variant
 Requires: /sbin/nologin
 
 BuildRequires: autoconf, automake, perl-interpreter, perl-generators, zlib-devel
@@ -229,7 +253,6 @@ BuildRequires: systemd-rpm-macros
 BuildRequires: gcc make
 BuildRequires: p11-kit-devel
 BuildRequires: libfido2-devel
-Recommends: p11-kit
 
 %if %{kerberos5}
 BuildRequires: krb5-devel
@@ -394,6 +417,14 @@ gpgv2 --quiet --keyring %{SOURCE3} %{SOURCE1} %{SOURCE0}
 %patch -P 1033 -p1 -b .reject-null-char-in-url-string
 %patch -P 1034 -p1 -b .sshd-nogsscreds
 %patch -P 1035 -p1 -b .mlkem-nist-fips
+%patch -P 1037 -p1 -b .first-match-wins
+%patch -P 1038 -p1 -b .maxstartups-mistracking
+%patch -P 1039 -p1 -b .fill-default-options-error
+%patch -P 1040 -p1 -b .scp-clear-setuid
+%patch -P 1041 -p1 -b .mux-askpass-check
+%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 100 -p1 -b .coverity
 
@@ -619,6 +650,9 @@ fi
 %ghost %attr(0644,root,root) %{_localstatedir}/lib/.gsissh-host-keys-migration
 
 %changelog
+* Fri May 29 2026 Mattias Ellert <mattias.ellert@physics.uu.se> - 9.9p1-6
+- Based on openssh-9.9p1-26.el10
+
 * Tue Mar 24 2026 Mattias Ellert <mattias.ellert@physics.uu.se> - 9.9p1-5
 - Based on openssh-9.9p1-19.el10
 

diff --git a/openssh-10.0-mlkem-nist-fips.patch b/openssh-10.0-mlkem-nist-fips.patch
index b610b6e..951e367 100644
--- a/openssh-10.0-mlkem-nist-fips.patch
+++ b/openssh-10.0-mlkem-nist-fips.patch
@@ -1,17 +1,85 @@
+diff --git a/compat.c b/compat.c
+index 4e611dc39..b5f4cc685 100644
+--- a/compat.c
++++ b/compat.c
+@@ -36,6 +36,7 @@
+ #include "compat.h"
+ #include "log.h"
+ #include "match.h"
++#include <openssl/fips.h>
+ 
+ /* determine bug flags from SSH protocol banner */
+ void
+@@ -148,8 +149,9 @@ char *
+ compat_kex_proposal(struct ssh *ssh, const char *p)
+ {
+ 	char *cp = NULL, *cp2 = NULL;
++	int mlkem_available = is_mlkem768_available();
+ 
+-	if ((ssh->compat & (SSH_BUG_CURVE25519PAD|SSH_OLD_DHGEX)) == 0)
++	if ((ssh->compat & (SSH_BUG_CURVE25519PAD|SSH_OLD_DHGEX)) == 0 && mlkem_available == 2)
+ 		return xstrdup(p);
+ 	debug2_f("original KEX proposal: %s", p);
+ 	if ((ssh->compat & SSH_BUG_CURVE25519PAD) != 0)
+@@ -164,6 +166,25 @@ compat_kex_proposal(struct ssh *ssh, const char *p)
+ 		free(cp);
+ 		cp = cp2;
+ 	}
++	if (mlkem_available == 2)
++		return cp ? cp : xstrdup(p);
++	if (mlkem_available == 1 && FIPS_mode()) {
++		if ((cp2 = match_filter_denylist(cp ? cp : p,
++		    "mlkem768x25519-sha256")) == NULL)
++			fatal("match_filter_denylist failed");
++		free(cp);
++		cp = cp2;
++	}
++	if (mlkem_available == 0) {
++		if ((cp2 = match_filter_denylist(cp ? cp : p,
++		    "mlkem768x25519-sha256,"
++		    "mlkem768nistp256-sha256,"
++		    "mlkem1024nistp384-sha384")) == NULL)
++			fatal("match_filter_denylist failed");
++		free(cp);
++		cp = cp2;
++	}
++
+ 	if (cp == NULL || *cp == '\0')
+ 		fatal("No supported key exchange algorithms found");
+ 	debug2_f("compat KEX proposal: %s", cp);
+diff --git a/compat.h b/compat.h
+index 2e6db5bf9..b78e55b69 100644
+--- a/compat.h
++++ b/compat.h
+@@ -62,4 +62,5 @@ struct ssh;
+ 
+ void    compat_banner(struct ssh *, const char *);
+ char	*compat_kex_proposal(struct ssh *, const char *);
++int is_mlkem768_available(void);
+ #endif
 diff --git a/kex-names.c b/kex-names.c
 index a728e0b38..9b852e8ab 100644
 --- a/kex-names.c
 +++ b/kex-names.c
-@@ -112,13 +112,30 @@ static const struct kexalg gss_kexalgs[] = {
+@@ -35,6 +35,7 @@
+ #include <openssl/crypto.h>
+ #include <openssl/fips.h>
+ #include <openssl/evp.h>
++#include <openssl/err.h>
+ #endif
+ 
+ #include "kex.h"
+@@ -113,14 +113,27 @@ static const struct kexalg gss_kexalgs[]
  	{ NULL, 0, -1, -1},
  };
  
 +/*
 + * 0 - unavailable
 + * 1 - available in non-FIPS mode
-+ * 2 - available in FIPS mode
++ * 2 - available always
 + */
- static int is_mlkem768_available()
+-static int is_mlkem768_available()
++int is_mlkem768_available()
  {
  	static int is_fetched = -1;
  
@@ -20,21 +88,18 @@ index a728e0b38..9b852e8ab 100644
 -		is_fetched = mlkem768 != NULL ? 1 : 0;
 +		EVP_KEM *mlkem768 = NULL;
 +
-+		if (FIPS_mode() == 1) {
-+		    mlkem768 = EVP_KEM_fetch(NULL, "mlkem768", NULL);
-+		    is_fetched = mlkem768 != NULL ? 2 : 0;
-+
-+		    if (is_fetched == 0) {
-+		        mlkem768 = EVP_KEM_fetch(NULL, "mlkem768", "provider=default,-fips");
-+		        is_fetched = mlkem768 != NULL ? 1 : 0;
-+		    }
-+		} else {
-+		    mlkem768 = EVP_KEM_fetch(NULL, "mlkem768", NULL);
-+		    is_fetched = mlkem768 != NULL ? 1 : 0;
++		ERR_set_mark();
++		mlkem768 = EVP_KEM_fetch(NULL, "mlkem768", NULL);
++		is_fetched = (mlkem768 == NULL) ? 0 : 2;
++		if (is_fetched == 0 && FIPS_mode() == 1) {
++		    mlkem768 = EVP_KEM_fetch(NULL, "mlkem768", "provider=default,-fips");
++		    is_fetched = (mlkem768 == NULL) ? 0 : 1;
 +		}
  		EVP_KEM_free(mlkem768);
++		ERR_pop_to_mark();
  	}
  
+ 	return is_fetched;
 @@ -131,13 +148,32 @@ kex_alg_list_internal(char sep, const struct kexalg *algs)
  	char *ret = NULL, *tmp;
  	size_t nlen, rlen = 0;
@@ -108,6 +173,25 @@ index a728e0b38..9b852e8ab 100644
  
  	for (k = kexalgs; k->name != NULL; k++) {
  		if (strcmp(k->name, name) == 0)
+@@ -292,8 +295,16 @@ kex_names_valid(const char *names)
+ 	for ((p = strsep(&cp, ",")); p && *p != '\0';
+ 	    (p = strsep(&cp, ","))) {
+ 		if (kex_alg_by_name(p) == NULL) {
+-			if (FIPS_mode())
+-				error("\"%.100s\" is not allowed in FIPS mode", p);
++			if (FIPS_mode()) {
++				if ((strcmp(p, KEX_MLKEM768X25519_SHA256) == 0)
++				    || (strcmp(p, KEX_MLKEM768NISTP256_SHA256) == 0)
++				    || (strcmp(p, KEX_MLKEM1024NISTP384_SHA384) == 0)) {
++					debug("\"%.100s\" is not allowed in FIPS mode", p);
++					continue;
++				}
++				else
++					error("\"%.100s\" is not allowed in FIPS mode", p);
++			}
+ 			else
+ 				error("Unsupported KEX algorithm \"%.100s\"", p);
+ 			free(s);
 diff --git a/kexgen.c b/kexgen.c
 index 6e910f84f..4bc3f9faf 100644
 --- a/kexgen.c

diff --git a/openssh-10.0-mlkem-nist.patch b/openssh-10.0-mlkem-nist.patch
index 22b8ec6..cb873c6 100644
--- a/openssh-10.0-mlkem-nist.patch
+++ b/openssh-10.0-mlkem-nist.patch
@@ -676,7 +676,7 @@ index 670049dcd..463d18771 100644
 +	/* generate ECDH key pair, store server pubkey after ciphertext */
 +	server_key = nist_pkey_keygen(server_key_len);
 +
-+	if ((r = get_uncompressed_ec_pubkey(server_key, server_pub, server_key_len) != 0) ||
++	if ((server_key == NULL) || (r = get_uncompressed_ec_pubkey(server_key, server_pub, server_key_len) != 0) ||
 +	    (r = sshbuf_put(buf, secret, sizeof(secret))) != 0 ||
 +	    (r = sshbuf_put(server_blob, enc_out, enc_out_len) != 0)||
 +	    (r = sshbuf_put(server_blob, server_pub, server_key_len)) != 0)

diff --git a/openssh-6.7p1-coverity.patch b/openssh-6.7p1-coverity.patch
index ffe0c69..276cc43 100644
--- a/openssh-6.7p1-coverity.patch
+++ b/openssh-6.7p1-coverity.patch
@@ -159,6 +159,46 @@ diff -up openssh-8.7p1/openbsd-compat/bsd-pselect.c.coverity openssh-8.7p1/openb
 diff -up openssh-8.5p1/readconf.c.coverity openssh-8.5p1/readconf.c
 --- openssh-8.5p1/readconf.c.coverity	2021-03-24 12:03:33.778968131 +0100
 +++ openssh-8.5p1/readconf.c	2021-03-24 12:03:33.785968180 +0100
+@@ -749,12 +749,12 @@ match_cfg_line(Options *options, const c
+ 	debug2("checking match for '%s' host %s originally %s",
+ 	    full_line, host, original_host);
+ 	while ((attrib = argv_next(acp, avp)) != NULL) {
+-		attrib = oattrib = xstrdup(attrib);
+ 		/* Terminate on comment */
+ 		if (*attrib == '#') {
+ 			argv_consume(acp);
+ 			break;
+ 		}
++		attrib = oattrib = xstrdup(attrib);
+ 		arg = criteria = NULL;
+ 		this_result = 1;
+ 		if ((negate = (attrib[0] == '!')))
+@@ -793,7 +793,7 @@ match_cfg_line(Options *options, const c
+ 			debug3("%.200s line %d: %smatched '%s'",
+ 			    filename, linenum,
+ 			    this_result ? "" : "not ", oattrib);
+-			continue;
++			goto next;
+ 		}
+ 
+ 		/* Keep this list in sync with below */
+@@ -863,7 +863,7 @@ match_cfg_line(Options *options, const c
+ 				debug3("%.200s line %d: skipped exec "
+ 				    "\"%.100s\"", filename, linenum, cmd);
+ 				free(cmd);
+-				continue;
++				goto next;
+ 			}
+ 			r = execute_in_shell(cmd);
+ 			if (r == -1) {
+@@ -887,6 +887,7 @@ match_cfg_line(Options *options, const c
+ 		    criteria == NULL ? "" : " \"",
+ 		    criteria == NULL ? "" : criteria,
+ 		    criteria == NULL ? "" : "\"");
++next:
+ 		free(criteria);
+ 		free(oattrib);
+ 		oattrib = attrib = NULL;
 @@ -1847,6 +1847,7 @@ parse_pubkey_algos:
  			} else if (r != 0) {
  				error("%.200s line %d: glob failed for %s.",
@@ -170,6 +210,108 @@ diff -up openssh-8.5p1/readconf.c.coverity openssh-8.5p1/readconf.c
 diff -up openssh-7.4p1/servconf.c.coverity openssh-7.4p1/servconf.c
 --- openssh-7.4p1/servconf.c.coverity	2016-12-23 16:40:26.896788690 +0100
 +++ openssh-7.4p1/servconf.c	2016-12-23 16:40:26.901788691 +0100
+@@ -1120,12 +1120,12 @@ match_cfg_line(const char *full_line, in
+ 	}
+ 
+ 	while ((oattrib = argv_next(acp, avp)) != NULL) {
+-		attrib = xstrdup(oattrib);
+ 		/* Terminate on comment */
+-		if (*attrib == '#') {
++		if (*oattrib == '#') {
+ 			argv_consume(acp); /* mark all arguments consumed */
+ 			break;
+ 		}
++		attrib = xstrdup(oattrib);
+ 		arg = NULL;
+ 		attributes++;
+ 		/* Criterion "all" has no argument and must appear alone */
+@@ -1147,13 +1147,13 @@ match_cfg_line(const char *full_line, in
+ 		if (strcasecmp(attrib, "invalid-user") == 0) {
+ 			if (ci == NULL) {
+ 				result = 0;
+-				continue;
++				goto next;
+ 			}
+ 			if (ci->user_invalid == 0)
+ 				result = 0;
+ 			else
+ 				debug("matched invalid-user at line %d", line);
+-			continue;
++			goto next;
+ 		}
+ 
+ 		/* Keep this list in sync with below */
+@@ -1179,7 +1179,7 @@ match_cfg_line(const char *full_line, in
+ 		if (strcasecmp(attrib, "user") == 0) {
+ 			if (ci == NULL || (ci->test && ci->user == NULL)) {
+ 				result = 0;
+-				continue;
++				goto next;
+ 			}
+ 			if (ci->user == NULL)
+ 				match_test_missing_fatal("User", "user");
+@@ -1191,7 +1191,7 @@ match_cfg_line(const char *full_line, in
+ 		} else if (strcasecmp(attrib, "group") == 0) {
+ 			if (ci == NULL || (ci->test && ci->user == NULL)) {
+ 				result = 0;
+-				continue;
++				goto next;
+ 			}
+ 			if (ci->user == NULL)
+ 				match_test_missing_fatal("Group", "user");
+@@ -1205,7 +1205,7 @@ match_cfg_line(const char *full_line, in
+ 		} else if (strcasecmp(attrib, "host") == 0) {
+ 			if (ci == NULL || (ci->test && ci->host == NULL)) {
+ 				result = 0;
+-				continue;
++				goto next;
+ 			}
+ 			if (ci->host == NULL)
+ 				match_test_missing_fatal("Host", "host");
+@@ -1220,7 +1220,7 @@ match_cfg_line(const char *full_line, in
+ 					fatal("Invalid Match address argument "
+ 					    "'%s' at line %d", arg, line);
+ 				result = 0;
+-				continue;
++				goto next;
+ 			}
+ 			if (ci->address == NULL)
+ 				match_test_missing_fatal("Address", "addr");
+@@ -1244,7 +1244,7 @@ match_cfg_line(const char *full_line, in
+ 					    "argument '%s' at line %d", arg,
+ 					    line);
+ 				result = 0;
+-				continue;
++				goto next;
+ 			}
+ 			if (ci->laddress == NULL)
+ 				match_test_missing_fatal("LocalAddress",
+@@ -1272,7 +1272,7 @@ match_cfg_line(const char *full_line, in
+ 			}
+ 			if (ci == NULL || (ci->test && ci->lport == -1)) {
+ 				result = 0;
+-				continue;
++				goto next;
+ 			}
+ 			if (ci->lport == 0)
+ 				match_test_missing_fatal("LocalPort", "lport");
+@@ -1286,7 +1286,7 @@ match_cfg_line(const char *full_line, in
+ 		} else if (strcasecmp(attrib, "rdomain") == 0) {
+ 			if (ci == NULL || (ci->test && ci->rdomain == NULL)) {
+ 				result = 0;
+-				continue;
++				goto next;
+ 			}
+ 			if (ci->rdomain == NULL)
+ 				match_test_missing_fatal("RDomain", "rdomain");
+@@ -1300,6 +1300,7 @@ match_cfg_line(const char *full_line, in
+ 			result = -1;
+ 			goto out;
+ 		}
++next:
+ 		free(attrib);
+ 		attrib = NULL;
+ 	}
 @@ -1638,8 +1638,9 @@ process_server_config_line(ServerOptions
  		if (*activep && *charptr == NULL) {
  			*charptr = tilde_expand_filename(arg, getuid());
@@ -246,3 +388,22 @@ diff -up openssh-8.5p1/ssh-keygen.c.coverity openssh-8.5p1/ssh-keygen.c
  		} else {
  			if (strncasecmp(cp, "key:", 4) == 0) {
  				cp += 4;
+diff --color -ruNp a/sshd.c b/sshd.c
+--- a/sshd.c	2026-04-01 14:29:14.186736233 +0200
++++ b/sshd.c	2026-04-01 14:36:59.136881819 +0200
+@@ -1079,6 +1079,7 @@ server_accept_loop(int *sock_in, int *so
+ 				send_rexec_state(config_s[0], cfg);
+ 				close(config_s[0]);
+ 				free(pfd);
++				free(startup_pollfd);
+ 				return;
+ 			}
+ 
+@@ -1111,6 +1112,7 @@ server_accept_loop(int *sock_in, int *so
+ 				    log_stderr);
+ 				close(config_s[0]);
+ 				free(pfd);
++				free(startup_pollfd);
+ 				return;
+ 			}
+ 

diff --git a/openssh-7.6p1-audit.patch b/openssh-7.6p1-audit.patch
index 2c7ddc5..a32abc9 100644
--- a/openssh-7.6p1-audit.patch
+++ b/openssh-7.6p1-audit.patch
@@ -2093,7 +2093,7 @@ diff -up openssh-8.6p1/sshd-session.c.audit openssh-8.6p1/sshd-session.c
 +#endif /* WITH_OPENSSL */
 +      case KEY_ED25519_CERT:
 +      case KEY_ED25519:
-+              return (k->ed25519_pk != NULL);
++              return (k->ed25519_sk != NULL);
 +      default:
 +              /* fatal("key_is_private: bad key type %d", k->type); */
 +              return 0;

diff --git a/openssh-7.7p1-fips.patch b/openssh-7.7p1-fips.patch
index fcd0245..8d442a4 100644
--- a/openssh-7.7p1-fips.patch
+++ b/openssh-7.7p1-fips.patch
@@ -701,3 +701,29 @@ diff -up openssh-9.9p1/kex.c.xxx openssh-9.9p1/kex.c
  	if ((cp = kex_names_cat(kexalgos, ssh->kex->server ?
  	    "ext-info-s,kex-strict-s-v00@openssh.com" :
  	    "ext-info-c,kex-strict-c-v00@openssh.com")) == NULL)
+diff --color -ruNp a/ssh-keyscan.c b/ssh-keyscan.c
+--- a/ssh-keyscan.c	2026-03-18 13:58:55.708193373 +0100
++++ b/ssh-keyscan.c	2026-03-18 15:34:35.495942538 +0100
+@@ -22,6 +22,7 @@
+ #ifdef WITH_OPENSSL
+ #include <openssl/bn.h>
+ #endif
++#include <openssl/fips.h>
+ 
+ #include <limits.h>
+ #include <netdb.h>
+@@ -239,6 +240,14 @@ keygrab_ssh2(con *c)
+ 	char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT };
+ 	int r;
+ 
++	if (FIPS_mode()) {
++		myproposal[PROPOSAL_KEX_ALGS] = KEX_DEFAULT_KEX_FIPS;
++		myproposal[PROPOSAL_ENC_ALGS_CTOS] = KEX_FIPS_ENCRYPT;
++		myproposal[PROPOSAL_ENC_ALGS_STOC] = KEX_FIPS_ENCRYPT;
++		myproposal[PROPOSAL_MAC_ALGS_CTOS] = KEX_FIPS_MAC;
++		myproposal[PROPOSAL_MAC_ALGS_STOC] = KEX_FIPS_MAC;
++	}
++
+ 	switch (c->c_keytype) {
+ 	case KT_DSA:
+ 		myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ?

diff --git a/openssh-9.6p1-gssapi-keyex.patch b/openssh-9.6p1-gssapi-keyex.patch
index ef1f97e..5875943 100644
--- a/openssh-9.6p1-gssapi-keyex.patch
+++ b/openssh-9.6p1-gssapi-keyex.patch
@@ -1,6 +1,6 @@
 diff --color -ruNp a/auth2.c b/auth2.c
---- a/auth2.c	2024-09-16 11:45:56.858133241 +0200
-+++ b/auth2.c	2024-09-16 11:46:34.688939755 +0200
+--- a/auth2.c	2026-03-13 12:32:48.463830672 +0100
++++ b/auth2.c	2026-03-13 12:16:40.013559000 +0100
 @@ -71,6 +71,7 @@ extern Authmethod method_passwd;
  extern Authmethod method_kbdint;
  extern Authmethod method_hostbased;
@@ -18,8 +18,8 @@ diff --color -ruNp a/auth2.c b/auth2.c
  #endif
  	&method_passwd,
 diff --color -ruNp a/auth2-gss.c b/auth2-gss.c
---- a/auth2-gss.c	2024-09-16 11:45:56.858133241 +0200
-+++ b/auth2-gss.c	2024-09-16 11:46:34.689939776 +0200
+--- a/auth2-gss.c	2026-03-13 12:32:48.464158978 +0100
++++ b/auth2-gss.c	2026-03-13 12:16:40.011579476 +0100
 @@ -51,6 +51,7 @@
  #define SSH_GSSAPI_MAX_MECHS	2048
  
@@ -108,8 +108,8 @@ diff --color -ruNp a/auth2-gss.c b/auth2-gss.c
  	&methodcfg_gssapi,
  	userauth_gssapi,
 diff --color -ruNp a/auth2-methods.c b/auth2-methods.c
---- a/auth2-methods.c	2024-07-01 06:36:28.000000000 +0200
-+++ b/auth2-methods.c	2024-09-16 11:46:34.689939776 +0200
+--- a/auth2-methods.c	2024-09-20 00:20:48.000000000 +0200
++++ b/auth2-methods.c	2026-03-13 12:16:40.011621502 +0100
 @@ -50,6 +50,11 @@ struct authmethod_cfg methodcfg_pubkey =
  	&options.pubkey_authentication
  };
@@ -131,8 +131,8 @@ diff --color -ruNp a/auth2-methods.c b/auth2-methods.c
  #endif
  	&methodcfg_passwd,
 diff --color -ruNp a/auth.c b/auth.c
---- a/auth.c	2024-07-01 06:36:28.000000000 +0200
-+++ b/auth.c	2024-09-16 11:46:34.690939798 +0200
+--- a/auth.c	2024-09-20 00:20:48.000000000 +0200
++++ b/auth.c	2026-03-13 12:16:39.971971452 +0100
 @@ -356,7 +356,8 @@ auth_root_allowed(struct ssh *ssh, const
  	case PERMIT_NO_PASSWD:
  		if (strcmp(method, "publickey") == 0 ||
@@ -144,8 +144,8 @@ diff --color -ruNp a/auth.c b/auth.c
  		break;
  	case PERMIT_FORCED_ONLY:
 diff --color -ruNp a/canohost.c b/canohost.c
---- a/canohost.c	2024-07-01 06:36:28.000000000 +0200
-+++ b/canohost.c	2024-09-16 11:46:34.690939798 +0200
+--- a/canohost.c	2024-09-20 00:20:48.000000000 +0200
++++ b/canohost.c	2026-03-13 12:16:39.971614349 +0100
 @@ -35,6 +35,99 @@
  #include "canohost.h"
  #include "misc.h"
@@ -247,8 +247,8 @@ diff --color -ruNp a/canohost.c b/canohost.c
  ipv64_normalise_mapped(struct sockaddr_storage *addr, socklen_t *len)
  {
 diff --color -ruNp a/canohost.h b/canohost.h
---- a/canohost.h	2024-07-01 06:36:28.000000000 +0200
-+++ b/canohost.h	2024-09-16 11:46:34.690939798 +0200
+--- a/canohost.h	2024-09-20 00:20:48.000000000 +0200
++++ b/canohost.h	2026-03-13 12:16:39.973010227 +0100
 @@ -15,6 +15,9 @@
  #ifndef _CANOHOST_H
  #define _CANOHOST_H
@@ -260,8 +260,8 @@ diff --color -ruNp a/canohost.h b/canohost.h
  int		 get_peer_port(int);
  char		*get_local_ipaddr(int);
 diff --color -ruNp a/clientloop.c b/clientloop.c
---- a/clientloop.c	2024-07-01 06:36:28.000000000 +0200
-+++ b/clientloop.c	2024-09-16 11:46:34.690939798 +0200
+--- a/clientloop.c	2024-09-20 00:20:48.000000000 +0200
++++ b/clientloop.c	2026-03-13 12:16:39.973067475 +0100
 @@ -115,6 +115,10 @@
  #include "ssherr.h"
  #include "hostfile.h"
@@ -289,8 +289,8 @@ diff --color -ruNp a/clientloop.c b/clientloop.c
  		if (conn_in_ready)
  			client_process_net_input(ssh);
 diff --color -ruNp a/configure.ac b/configure.ac
---- a/configure.ac	2024-09-16 11:45:56.870133497 +0200
-+++ b/configure.ac	2024-09-16 11:46:34.691939819 +0200
+--- a/configure.ac	2026-03-13 12:32:48.476497111 +0100
++++ b/configure.ac	2026-03-13 12:16:39.974067978 +0100
 @@ -774,6 +774,30 @@ int main(void) { if (NSVersionOfRunTimeL
  	    [Use tunnel device compatibility to OpenBSD])
  	AC_DEFINE([SSH_TUN_PREPEND_AF], [1],
@@ -323,8 +323,8 @@ diff --color -ruNp a/configure.ac b/configure.ac
  	AC_CHECK_DECL([AU_IPv4], [],
  	    AC_DEFINE([AU_IPv4], [0], [System only supports IPv4 audit records])
 diff --color -ruNp a/gss-genr.c b/gss-genr.c
---- a/gss-genr.c	2024-07-01 06:36:28.000000000 +0200
-+++ b/gss-genr.c	2024-09-16 11:46:34.708940181 +0200
+--- a/gss-genr.c	2024-09-20 00:20:48.000000000 +0200
++++ b/gss-genr.c	2026-03-13 12:16:40.012672759 +0100
 @@ -42,9 +42,33 @@
  #include "sshbuf.h"
  #include "log.h"
@@ -710,8 +710,8 @@ diff --color -ruNp a/gss-genr.c b/gss-genr.c
 +
  #endif /* GSSAPI */
 diff --color -ruNp a/gss-serv.c b/gss-serv.c
---- a/gss-serv.c	2024-07-01 06:36:28.000000000 +0200
-+++ b/gss-serv.c	2024-09-16 11:46:34.692939840 +0200
+--- a/gss-serv.c	2024-09-20 00:20:48.000000000 +0200
++++ b/gss-serv.c	2026-03-13 12:16:39.978787818 +0100
 @@ -1,7 +1,7 @@
  /* $OpenBSD: gss-serv.c,v 1.32 2020/03/13 03:17:07 djm Exp $ */
  
@@ -1004,8 +1004,8 @@ diff --color -ruNp a/gss-serv.c b/gss-serv.c
  
  /* Privileged */
 diff --color -ruNp a/gss-serv-krb5.c b/gss-serv-krb5.c
---- a/gss-serv-krb5.c	2024-07-01 06:36:28.000000000 +0200
-+++ b/gss-serv-krb5.c	2024-09-16 11:46:34.692939840 +0200
+--- a/gss-serv-krb5.c	2024-09-20 00:20:48.000000000 +0200
++++ b/gss-serv-krb5.c	2026-03-13 12:16:39.978934056 +0100
 @@ -1,7 +1,7 @@
  /* $OpenBSD: gss-serv-krb5.c,v 1.9 2018/07/09 21:37:55 markus Exp $ */
  
@@ -1143,8 +1143,8 @@ diff --color -ruNp a/gss-serv-krb5.c b/gss-serv-krb5.c
  
  #endif /* KRB5 */
 diff --color -ruNp a/kex.c b/kex.c
---- a/kex.c	2024-07-01 06:36:28.000000000 +0200
-+++ b/kex.c	2024-09-16 11:46:34.692939840 +0200
+--- a/kex.c	2024-09-20 00:20:48.000000000 +0200
++++ b/kex.c	2026-03-13 12:16:39.978857653 +0100
 @@ -297,17 +297,37 @@ static int
  kex_compose_ext_info_server(struct ssh *ssh, struct sshbuf *m)
  {
@@ -1200,8 +1200,8 @@ diff --color -ruNp a/kex.c b/kex.c
  	sshkey_free(kex->initial_hostkey);
  	free(kex->failed_choice);
 diff --color -ruNp a/kexdh.c b/kexdh.c
---- a/kexdh.c	2024-07-01 06:36:28.000000000 +0200
-+++ b/kexdh.c	2024-09-16 11:46:34.693939862 +0200
+--- a/kexdh.c	2024-09-20 00:20:48.000000000 +0200
++++ b/kexdh.c	2026-03-13 12:16:39.979537228 +0100
 @@ -49,13 +49,23 @@ kex_dh_keygen(struct kex *kex)
  {
  	switch (kex->kex_type) {
@@ -1227,8 +1227,8 @@ diff --color -ruNp a/kexdh.c b/kexdh.c
  		break;
  	case KEX_DH_GRP18_SHA512:
 diff --color -ruNp a/kexgen.c b/kexgen.c
---- a/kexgen.c	2024-07-01 06:36:28.000000000 +0200
-+++ b/kexgen.c	2024-09-16 11:46:34.693939862 +0200
+--- a/kexgen.c	2024-09-20 00:20:48.000000000 +0200
++++ b/kexgen.c	2026-03-13 12:16:39.979737335 +0100
 @@ -44,7 +44,7 @@
  static int input_kex_gen_init(int, u_int32_t, struct ssh *);
  static int input_kex_gen_reply(int type, u_int32_t seq, struct ssh *ssh);
@@ -1240,7 +1240,7 @@ diff --color -ruNp a/kexgen.c b/kexgen.c
      const struct sshbuf *client_version,
 diff --color -ruNp a/kexgssc.c b/kexgssc.c
 --- a/kexgssc.c	1970-01-01 01:00:00.000000000 +0100
-+++ b/kexgssc.c	2024-10-14 15:18:02.491798105 +0200
++++ b/kexgssc.c	2026-03-13 12:25:23.115812190 +0100
 @@ -0,0 +1,706 @@
 +/*
 + * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
@@ -1369,7 +1369,7 @@ diff --color -ruNp a/kexgssc.c b/kexgssc.c
 +
 +	/* Verify that the hash matches the MIC we just got. */
 +	if (GSS_ERROR(ssh_gssapi_checkmic(gss, &gss->buf, &gss->msg_tok)))
-+		sshpkt_disconnect(ssh, "Hash's MIC didn't verify");
++		ssh_packet_disconnect(ssh, "Hash's MIC didn't verify");
 +
 +	gss_release_buffer(&gss->minor, &gss->msg_tok);
 +
@@ -1592,10 +1592,10 @@ diff --color -ruNp a/kexgssc.c b/kexgssc.c
 +			fatal("Failed to read token: %s", ssh_err(r));
 +		/* If we're already complete - protocol error */
 +		if (gss->major == GSS_S_COMPLETE)
-+			sshpkt_disconnect(ssh, "Protocol error: received token when complete");
++			ssh_packet_disconnect(ssh, "Protocol error: received token when complete");
 +	} else {
 +		if (gss->major != GSS_S_COMPLETE)
-+			sshpkt_disconnect(ssh, "Protocol error: did not receive final token");
++			ssh_packet_disconnect(ssh, "Protocol error: did not receive final token");
 +	}
 +	if ((r = sshpkt_get_end(ssh)) != 0)
 +		fatal("Expecting end of packet.");
@@ -1731,7 +1731,7 @@ diff --color -ruNp a/kexgssc.c b/kexgssc.c
 +
 +	/* Verify that the hash matches the MIC we just got. */
 +	if (GSS_ERROR(ssh_gssapi_checkmic(gss, &gss->buf, &gss->msg_tok)))
-+		sshpkt_disconnect(ssh, "Hash's MIC didn't verify");
++		ssh_packet_disconnect(ssh, "Hash's MIC didn't verify");
 +
 +	gss_release_buffer(&gss->minor, &gss->msg_tok);
 +
@@ -1932,10 +1932,10 @@ diff --color -ruNp a/kexgssc.c b/kexgssc.c
 +			fatal("Failed to read token: %s", ssh_err(r));
 +		/* If we're already complete - protocol error */
 +		if (gss->major == GSS_S_COMPLETE)
-+			sshpkt_disconnect(ssh, "Protocol error: received token when complete");
++			ssh_packet_disconnect(ssh, "Protocol error: received token when complete");
 +	} else {
 +		if (gss->major != GSS_S_COMPLETE)
-+			sshpkt_disconnect(ssh, "Protocol error: did not receive final token");
++			ssh_packet_disconnect(ssh, "Protocol error: did not receive final token");
 +	}
 +	if ((r = sshpkt_get_end(ssh)) != 0)
 +		fatal("Expecting end of packet.");
@@ -1950,8 +1950,8 @@ diff --color -ruNp a/kexgssc.c b/kexgssc.c
 +#endif /* defined(GSSAPI) && defined(WITH_OPENSSL) */
 diff --color -ruNp a/kexgsss.c b/kexgsss.c
 --- a/kexgsss.c	1970-01-01 01:00:00.000000000 +0100
-+++ b/kexgsss.c	2024-10-14 15:18:02.491798105 +0200
-@@ -0,0 +1,601 @@
++++ b/kexgsss.c	2026-03-13 12:32:17.556172591 +0100
+@@ -0,0 +1,603 @@
 +/*
 + * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
 + *
@@ -2083,7 +2083,7 @@ diff --color -ruNp a/kexgsss.c b/kexgsss.c
 +{
 +	struct kex *kex = ssh->kex;
 +	Gssctxt *gss = kex->gss;
-+	gss_buffer_desc msg_tok;
++	gss_buffer_desc msg_tok = GSS_C_EMPTY_BUFFER;
 +	u_char hash[SSH_DIGEST_MAX_LENGTH];
 +	size_t hashlen;
 +	struct sshbuf *shared_secret = NULL;
@@ -2167,7 +2167,8 @@ diff --color -ruNp a/kexgsss.c b/kexgsss.c
 +	Gssctxt *gss = kex->gss;
 +	struct sshbuf *empty;
 +	struct sshbuf *client_pubkey = NULL;
-+	gss_buffer_desc recv_tok, send_tok = GSS_C_EMPTY_BUFFER;
++	gss_buffer_desc recv_tok = GSS_C_EMPTY_BUFFER;
++	gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
 +	OM_uint32 ret_flags = 0;
 +	int r;
 +
@@ -2243,7 +2244,8 @@ diff --color -ruNp a/kexgsss.c b/kexgsss.c
 +		      struct ssh *ssh)
 +{
 +	Gssctxt *gss = ssh->kex->gss;
-+	gss_buffer_desc recv_tok, send_tok = GSS_C_EMPTY_BUFFER;
++	gss_buffer_desc recv_tok = GSS_C_EMPTY_BUFFER;
++	gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
 +	OM_uint32 ret_flags = 0;
 +	int r;
 +
@@ -2334,7 +2336,7 @@ diff --color -ruNp a/kexgsss.c b/kexgsss.c
 +{
 +	struct kex *kex = ssh->kex;
 +	Gssctxt *gss = kex->gss;
-+	gss_buffer_desc msg_tok;
++	gss_buffer_desc msg_tok = GSS_C_EMPTY_BUFFER;
 +	u_char hash[SSH_DIGEST_MAX_LENGTH];
 +	size_t hashlen;
 +	const BIGNUM *pub_key, *dh_p, *dh_g;
@@ -2475,10 +2477,8 @@ diff --color -ruNp a/kexgsss.c b/kexgsss.c
 +		fatal("GSS_GEX, bad parameters: %d !< %d !< %d", min, nbits, max);
 +
 +	kex->dh = mm_choose_dh(min, nbits, max);
-+	if (kex->dh == NULL) {
-+		sshpkt_disconnect(ssh, "Protocol error: no matching group found");
-+		fatal("Protocol error: no matching group found");
-+	}
++	if (kex->dh == NULL)
++		ssh_packet_disconnect(ssh, "Protocol error: no matching group found");
 +
 +	DH_get0_pqg(kex->dh, &dh_p, NULL, &dh_g);
 +	if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_GROUP)) != 0 ||
@@ -2510,7 +2510,8 @@ diff --color -ruNp a/kexgsss.c b/kexgsss.c
 +		     struct ssh *ssh)
 +{
 +	Gssctxt *gss = ssh->kex->gss;
-+	gss_buffer_desc recv_tok, send_tok = GSS_C_EMPTY_BUFFER;
++	gss_buffer_desc recv_tok = GSS_C_EMPTY_BUFFER;
++	gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
 +	OM_uint32 ret_flags = 0;
 +	int r;
 +
@@ -2537,7 +2538,8 @@ diff --color -ruNp a/kexgsss.c b/kexgsss.c
 +			 struct ssh *ssh)
 +{
 +	Gssctxt *gss = ssh->kex->gss;
-+	gss_buffer_desc recv_tok, send_tok = GSS_C_EMPTY_BUFFER;
++	gss_buffer_desc recv_tok = GSS_C_EMPTY_BUFFER;
++	gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
 +	OM_uint32 ret_flags = 0;
 +	int r;
 +
@@ -2554,8 +2556,8 @@ diff --color -ruNp a/kexgsss.c b/kexgsss.c
 +
 +#endif /* defined(GSSAPI) && defined(WITH_OPENSSL) */
 diff --color -ruNp a/kex.h b/kex.h
---- a/kex.h	2024-07-01 06:36:28.000000000 +0200
-+++ b/kex.h	2024-09-16 11:46:34.710940224 +0200
+--- a/kex.h	2024-09-20 00:20:48.000000000 +0200
++++ b/kex.h	2026-03-13 12:16:40.013688997 +0100
 @@ -29,6 +29,10 @@
  #include "mac.h"
  #include "crypto_api.h"
@@ -2567,7 +2569,7 @@ diff --color -ruNp a/kex.h b/kex.h
  #ifdef WITH_OPENSSL
  # include <openssl/bn.h>
  # include <openssl/dh.h>
-@@ -102,6 +106,15 @@ enum kex_exchange {
+@@ -103,6 +107,15 @@ enum kex_exchange {
  	KEX_C25519_SHA256,
  	KEX_KEM_SNTRUP761X25519_SHA512,
  	KEX_KEM_MLKEM768X25519_SHA256,
@@ -2583,7 +2585,7 @@ diff --color -ruNp a/kex.h b/kex.h
  	KEX_MAX
  };
  
-@@ -164,6 +177,13 @@ struct kex {
+@@ -165,6 +178,13 @@ struct kex {
  	u_int	flags;
  	int	hash_alg;
  	int	ec_nid;
@@ -2597,7 +2599,7 @@ diff --color -ruNp a/kex.h b/kex.h
  	char	*failed_choice;
  	int	(*verify_host_key)(struct sshkey *, struct ssh *);
  	struct sshkey *(*load_host_public_key)(int, int, struct ssh *);
-@@ -189,8 +209,10 @@ int	 kex_hash_from_name(const char *);
+@@ -191,8 +211,10 @@ int	 kex_hash_from_name(const char *);
  int	 kex_nid_from_name(const char *);
  int	 kex_names_valid(const char *);
  char	*kex_alg_list(char);
@@ -2608,7 +2610,7 @@ diff --color -ruNp a/kex.h b/kex.h
  int	 kex_assemble_names(char **, const char *, const char *);
  void	 kex_proposal_populate_entries(struct ssh *, char *prop[PROPOSAL_MAX],
      const char *, const char *, const char *, const char *, const char *);
-@@ -224,6 +246,12 @@ int	 kexgex_client(struct ssh *);
+@@ -226,6 +248,12 @@ int	 kexgex_client(struct ssh *);
  int	 kexgex_server(struct ssh *);
  int	 kex_gen_client(struct ssh *);
  int	 kex_gen_server(struct ssh *);
@@ -2621,7 +2623,7 @@ diff --color -ruNp a/kex.h b/kex.h
  
  int	 kex_dh_keypair(struct kex *);
  int	 kex_dh_enc(struct kex *, const struct sshbuf *, struct sshbuf **,
-@@ -256,6 +284,12 @@ int	 kexgex_hash(int, const struct sshbu
+@@ -264,6 +292,12 @@ int	 kexgex_hash(int, const struct sshbu
      const BIGNUM *, const u_char *, size_t,
      u_char *, size_t *);
  
@@ -2635,8 +2637,8 @@ diff --color -ruNp a/kex.h b/kex.h
  	__attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE)))
  	__attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE)));
 diff --color -ruNp a/kex-names.c b/kex-names.c
---- a/kex-names.c	2024-07-01 06:36:28.000000000 +0200
-+++ b/kex-names.c	2024-09-16 11:46:34.694939883 +0200
+--- a/kex-names.c	2024-09-20 00:20:48.000000000 +0200
++++ b/kex-names.c	2026-03-13 12:16:39.979603048 +0100
 @@ -45,6 +45,10 @@
  #include "ssherr.h"
  #include "xmalloc.h"
@@ -2648,7 +2650,7 @@ diff --color -ruNp a/kex-names.c b/kex-names.c
  struct kexalg {
  	char *name;
  	u_int type;
-@@ -83,15 +87,28 @@ static const struct kexalg kexalgs[] = {
+@@ -89,15 +93,28 @@ static const struct kexalg kexalgs[] = {
  #endif /* HAVE_EVP_SHA256 || !WITH_OPENSSL */
  	{ NULL, 0, -1, -1},
  };
@@ -2680,7 +2682,7 @@ diff --color -ruNp a/kex-names.c b/kex-names.c
  		if (ret != NULL)
  			ret[rlen++] = sep;
  		nlen = strlen(k->name);
-@@ -106,6 +123,18 @@ kex_alg_list(char sep)
+@@ -112,6 +129,18 @@ kex_alg_list(char sep)
  	return ret;
  }
  
@@ -2699,7 +2701,7 @@ diff --color -ruNp a/kex-names.c b/kex-names.c
  static const struct kexalg *
  kex_alg_by_name(const char *name)
  {
-@@ -115,6 +144,10 @@ kex_alg_by_name(const char *name)
+@@ -121,6 +150,10 @@ kex_alg_by_name(const char *name)
  		if (strcmp(k->name, name) == 0)
  			return k;
  	}
@@ -2710,7 +2712,7 @@ diff --color -ruNp a/kex-names.c b/kex-names.c
  	return NULL;
  }
  
-@@ -328,3 +361,26 @@ kex_assemble_names(char **listp, const c
+@@ -334,3 +367,26 @@ kex_assemble_names(char **listp, const c
  	free(ret);
  	return r;
  }
@@ -2738,8 +2740,8 @@ diff --color -ruNp a/kex-names.c b/kex-names.c
 +	return 1;
 +}
 diff --color -ruNp a/Makefile.in b/Makefile.in
---- a/Makefile.in	2024-09-16 11:45:56.868133454 +0200
-+++ b/Makefile.in	2024-09-16 11:46:34.695939904 +0200
+--- a/Makefile.in	2026-03-13 12:32:48.475081074 +0100
++++ b/Makefile.in	2026-03-13 12:16:39.979453307 +0100
 @@ -114,6 +114,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \
  	kex.o kex-names.o kexdh.o kexgex.o kexecdh.o kexc25519.o \
  	kexgexc.o kexgexs.o \
@@ -2767,9 +2769,9 @@ diff --color -ruNp a/Makefile.in b/Makefile.in
  regress/modpipe$(EXEEXT): $(srcdir)/regress/modpipe.c $(REGRESSLIBS)
  	$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $(srcdir)/regress/modpipe.c \
 diff --color -ruNp a/monitor.c b/monitor.c
---- a/monitor.c	2024-09-16 11:45:56.861133305 +0200
-+++ b/monitor.c	2024-09-16 11:46:34.696939926 +0200
-@@ -143,6 +143,8 @@ int mm_answer_gss_setup_ctx(struct ssh *
+--- a/monitor.c	2026-03-13 12:32:48.467311058 +0100
++++ b/monitor.c	2026-03-13 12:16:40.012477799 +0100
+@@ -144,6 +144,8 @@ int mm_answer_gss_setup_ctx(struct ssh *
  int mm_answer_gss_accept_ctx(struct ssh *, int, struct sshbuf *);
  int mm_answer_gss_userok(struct ssh *, int, struct sshbuf *);
  int mm_answer_gss_checkmic(struct ssh *, int, struct sshbuf *);
@@ -2778,7 +2780,7 @@ diff --color -ruNp a/monitor.c b/monitor.c
  #endif
  
  #ifdef SSH_AUDIT_EVENTS
-@@ -219,11 +221,18 @@ struct mon_table mon_dispatch_proto20[]
+@@ -220,11 +222,18 @@ struct mon_table mon_dispatch_proto20[]
      {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx},
      {MONITOR_REQ_GSSUSEROK, MON_ONCE|MON_AUTHDECIDE, mm_answer_gss_userok},
      {MONITOR_REQ_GSSCHECKMIC, MON_ONCE, mm_answer_gss_checkmic},
@@ -2797,7 +2799,7 @@ diff --color -ruNp a/monitor.c b/monitor.c
  #ifdef WITH_OPENSSL
      {MONITOR_REQ_MODULI, 0, mm_answer_moduli},
  #endif
-@@ -292,6 +301,10 @@ monitor_child_preauth(struct ssh *ssh, s
+@@ -293,6 +302,10 @@ monitor_child_preauth(struct ssh *ssh, s
  	/* Permit requests for moduli and signatures */
  	monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
  	monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
@@ -2808,7 +2810,7 @@ diff --color -ruNp a/monitor.c b/monitor.c
  
  	/* The first few requests do not require asynchronous access */
  	while (!authenticated) {
-@@ -344,8 +357,15 @@ monitor_child_preauth(struct ssh *ssh, s
+@@ -345,8 +358,15 @@ monitor_child_preauth(struct ssh *ssh, s
  		if (ent->flags & (MON_AUTHDECIDE|MON_ALOG)) {
  			auth_log(ssh, authenticated, partial,
  			    auth_method, auth_submethod);
@@ -2825,7 +2827,7 @@ diff --color -ruNp a/monitor.c b/monitor.c
  			if (authenticated || partial) {
  				auth2_update_session_info(authctxt,
  				    auth_method, auth_submethod);
-@@ -413,6 +433,10 @@ monitor_child_postauth(struct ssh *ssh,
+@@ -414,6 +434,10 @@ monitor_child_postauth(struct ssh *ssh,
  	monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
  	monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
  	monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
@@ -2836,7 +2838,7 @@ diff --color -ruNp a/monitor.c b/monitor.c
  
  	if (auth_opts->permit_pty_flag) {
  		monitor_permit(mon_dispatch, MONITOR_REQ_PTY, 1);
-@@ -1793,6 +1817,17 @@ monitor_apply_keystate(struct ssh *ssh,
+@@ -1803,6 +1827,17 @@ monitor_apply_keystate(struct ssh *ssh,
  # ifdef OPENSSL_HAS_ECC
  	kex->kex[KEX_ECDH_SHA2] = kex_gen_server;
  # endif
@@ -2854,7 +2856,7 @@ diff --color -ruNp a/monitor.c b/monitor.c
  #endif /* WITH_OPENSSL */
  	kex->kex[KEX_C25519_SHA256] = kex_gen_server;
  	kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_server;
-@@ -1885,8 +1920,8 @@ mm_answer_gss_setup_ctx(struct ssh *ssh,
+@@ -1896,8 +1931,8 @@ mm_answer_gss_setup_ctx(struct ssh *ssh,
  	u_char *p;
  	int r;
  
@@ -2865,7 +2867,7 @@ diff --color -ruNp a/monitor.c b/monitor.c
  
  	if ((r = sshbuf_get_string(m, &p, &len)) != 0)
  		fatal_fr(r, "parse");
-@@ -1918,8 +1953,8 @@ mm_answer_gss_accept_ctx(struct ssh *ssh
+@@ -1929,8 +1964,8 @@ mm_answer_gss_accept_ctx(struct ssh *ssh
  	OM_uint32 flags = 0; /* GSI needs this */
  	int r;
  
@@ -2876,7 +2878,7 @@ diff --color -ruNp a/monitor.c b/monitor.c
  
  	if ((r = ssh_gssapi_get_buffer_desc(m, &in)) != 0)
  		fatal_fr(r, "ssh_gssapi_get_buffer_desc");
-@@ -1939,6 +1974,7 @@ mm_answer_gss_accept_ctx(struct ssh *ssh
+@@ -1950,6 +1985,7 @@ mm_answer_gss_accept_ctx(struct ssh *ssh
  		monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0);
  		monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1);
  		monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1);
@@ -2884,7 +2886,7 @@ diff --color -ruNp a/monitor.c b/monitor.c
  	}
  	return (0);
  }
-@@ -1950,8 +1986,8 @@ mm_answer_gss_checkmic(struct ssh *ssh,
+@@ -1961,8 +1997,8 @@ mm_answer_gss_checkmic(struct ssh *ssh,
  	OM_uint32 ret;
  	int r;
  
@@ -2895,7 +2897,7 @@ diff --color -ruNp a/monitor.c b/monitor.c
  
  	if ((r = ssh_gssapi_get_buffer_desc(m, &gssbuf)) != 0 ||
  	    (r = ssh_gssapi_get_buffer_desc(m, &mic)) != 0)
-@@ -1977,13 +2013,17 @@ mm_answer_gss_checkmic(struct ssh *ssh,
+@@ -1988,13 +2024,17 @@ mm_answer_gss_checkmic(struct ssh *ssh,
  int
  mm_answer_gss_userok(struct ssh *ssh, int sock, struct sshbuf *m)
  {
@@ -2917,7 +2919,7 @@ diff --color -ruNp a/monitor.c b/monitor.c
  
  	sshbuf_reset(m);
  	if ((r = sshbuf_put_u32(m, authenticated)) != 0)
-@@ -1992,7 +2032,11 @@ mm_answer_gss_userok(struct ssh *ssh, in
+@@ -2003,7 +2043,11 @@ mm_answer_gss_userok(struct ssh *ssh, in
  	debug3_f("sending result %d", authenticated);
  	mm_request_send(sock, MONITOR_ANS_GSSUSEROK, m);
  
@@ -2930,7 +2932,7 @@ diff --color -ruNp a/monitor.c b/monitor.c
  
  	if ((displayname = ssh_gssapi_displayname()) != NULL)
  		auth2_record_info(authctxt, "%s", displayname);
-@@ -2000,5 +2044,84 @@ mm_answer_gss_userok(struct ssh *ssh, in
+@@ -2011,5 +2055,84 @@ mm_answer_gss_userok(struct ssh *ssh, in
  	/* Monitor loop will terminate if authenticated */
  	return (authenticated);
  }
@@ -3016,8 +3018,8 @@ diff --color -ruNp a/monitor.c b/monitor.c
  #endif /* GSSAPI */
  
 diff --color -ruNp a/monitor.h b/monitor.h
---- a/monitor.h	2024-09-16 11:45:56.861133305 +0200
-+++ b/monitor.h	2024-09-16 11:46:34.696939926 +0200
+--- a/monitor.h	2026-03-13 12:32:48.467853845 +0100
++++ b/monitor.h	2026-03-13 12:16:40.011929029 +0100
 @@ -67,6 +67,8 @@ enum monitor_reqtype {
  	MONITOR_REQ_PAM_FREE_CTX = 110, MONITOR_ANS_PAM_FREE_CTX = 111,
  	MONITOR_REQ_AUDIT_EVENT = 112, MONITOR_REQ_AUDIT_COMMAND = 113,
@@ -3028,8 +3030,8 @@ diff --color -ruNp a/monitor.h b/monitor.h
  
  struct ssh;
 diff --color -ruNp a/monitor_wrap.c b/monitor_wrap.c
---- a/monitor_wrap.c	2024-09-16 11:45:56.862133326 +0200
-+++ b/monitor_wrap.c	2024-09-16 11:46:34.697939947 +0200
+--- a/monitor_wrap.c	2026-03-13 12:32:48.468148305 +0100
++++ b/monitor_wrap.c	2026-03-13 12:16:40.011969272 +0100
 @@ -1075,13 +1075,15 @@ mm_ssh_gssapi_checkmic(Gssctxt *ctx, gss
  }
  
@@ -3108,8 +3110,8 @@ diff --color -ruNp a/monitor_wrap.c b/monitor_wrap.c
  
  /*
 diff --color -ruNp a/monitor_wrap.h b/monitor_wrap.h
---- a/monitor_wrap.h	2024-09-16 11:45:56.862133326 +0200
-+++ b/monitor_wrap.h	2024-09-16 11:46:34.697939947 +0200
+--- a/monitor_wrap.h	2026-03-13 12:32:48.468446940 +0100
++++ b/monitor_wrap.h	2026-03-13 12:16:40.012015851 +0100
 @@ -67,8 +67,10 @@ void mm_decode_activate_server_options(s
  OM_uint32 mm_ssh_gssapi_server_ctx(Gssctxt **, gss_OID);
  OM_uint32 mm_ssh_gssapi_accept_ctx(Gssctxt *,
@@ -3123,8 +3125,8 @@ diff --color -ruNp a/monitor_wrap.h b/monitor_wrap.h
  
  #ifdef USE_PAM
 diff --color -ruNp a/readconf.c b/readconf.c
---- a/readconf.c	2024-07-01 06:36:28.000000000 +0200
-+++ b/readconf.c	2024-09-16 11:46:34.699939990 +0200
+--- a/readconf.c	2024-09-20 00:20:48.000000000 +0200
++++ b/readconf.c	2026-03-13 12:16:40.012058137 +0100
 @@ -70,6 +70,7 @@
  #include "uidswap.h"
  #include "myproposal.h"
@@ -3165,7 +3167,7 @@ diff --color -ruNp a/readconf.c b/readconf.c
  #endif
  #ifdef ENABLE_PKCS11
  	{ "pkcs11provider", oPKCS11Provider },
-@@ -1227,10 +1242,42 @@ parse_time:
+@@ -1256,10 +1271,42 @@ parse_time:
  		intptr = &options->gss_authentication;
  		goto parse_flag;
  
@@ -3208,7 +3210,7 @@ diff --color -ruNp a/readconf.c b/readconf.c
  	case oBatchMode:
  		intptr = &options->batch_mode;
  		goto parse_flag;
-@@ -2542,7 +2589,13 @@ initialize_options(Options * options)
+@@ -2576,7 +2623,13 @@ initialize_options(Options * options)
  	options->fwd_opts.streamlocal_bind_unlink = -1;
  	options->pubkey_authentication = -1;
  	options->gss_authentication = -1;
@@ -3222,7 +3224,7 @@ diff --color -ruNp a/readconf.c b/readconf.c
  	options->password_authentication = -1;
  	options->kbd_interactive_authentication = -1;
  	options->kbd_interactive_devices = NULL;
-@@ -2705,8 +2758,18 @@ fill_default_options(Options * options)
+@@ -2739,8 +2792,18 @@ fill_default_options(Options * options)
  		options->pubkey_authentication = SSH_PUBKEY_AUTH_ALL;
  	if (options->gss_authentication == -1)
  		options->gss_authentication = 0;
@@ -3241,7 +3243,7 @@ diff --color -ruNp a/readconf.c b/readconf.c
  	if (options->password_authentication == -1)
  		options->password_authentication = 1;
  	if (options->kbd_interactive_authentication == -1)
-@@ -3533,7 +3596,14 @@ dump_client_config(Options *o, const cha
+@@ -3567,7 +3630,14 @@ dump_client_config(Options *o, const cha
  	dump_cfg_fmtint(oGatewayPorts, o->fwd_opts.gateway_ports);
  #ifdef GSSAPI
  	dump_cfg_fmtint(oGssAuthentication, o->gss_authentication);
@@ -3257,8 +3259,8 @@ diff --color -ruNp a/readconf.c b/readconf.c
  	dump_cfg_fmtint(oHashKnownHosts, o->hash_known_hosts);
  	dump_cfg_fmtint(oHostbasedAuthentication, o->hostbased_authentication);
 diff --color -ruNp a/readconf.h b/readconf.h
---- a/readconf.h	2024-07-01 06:36:28.000000000 +0200
-+++ b/readconf.h	2024-09-16 11:46:34.699939990 +0200
+--- a/readconf.h	2024-09-20 00:20:48.000000000 +0200
++++ b/readconf.h	2026-03-13 12:16:39.991140430 +0100
 @@ -40,7 +40,13 @@ typedef struct {
  	int     pubkey_authentication;	/* Try ssh2 pubkey authentication. */
  	int     hostbased_authentication;	/* ssh2's rhosts_rsa */
@@ -3274,8 +3276,8 @@ diff --color -ruNp a/readconf.h b/readconf.h
  						 * authentication. */
  	int     kbd_interactive_authentication; /* Try keyboard-interactive auth. */
 diff --color -ruNp a/servconf.c b/servconf.c
---- a/servconf.c	2024-07-01 06:36:28.000000000 +0200
-+++ b/servconf.c	2024-09-16 11:46:34.700940011 +0200
+--- a/servconf.c	2024-09-20 00:20:48.000000000 +0200
++++ b/servconf.c	2026-03-13 12:16:39.991185528 +0100
 @@ -68,6 +68,7 @@
  #include "auth.h"
  #include "myproposal.h"
@@ -3296,7 +3298,7 @@ diff --color -ruNp a/servconf.c b/servconf.c
  	options->password_authentication = -1;
  	options->kbd_interactive_authentication = -1;
  	options->permit_empty_passwd = -1;
-@@ -376,10 +380,18 @@ fill_default_server_options(ServerOption
+@@ -378,10 +382,18 @@ fill_default_server_options(ServerOption
  		options->kerberos_get_afs_token = 0;
  	if (options->gss_authentication == -1)
  		options->gss_authentication = 0;
@@ -3315,7 +3317,7 @@ diff --color -ruNp a/servconf.c b/servconf.c
  	if (options->password_authentication == -1)
  		options->password_authentication = 1;
  	if (options->kbd_interactive_authentication == -1)
-@@ -558,6 +570,7 @@ typedef enum {
+@@ -564,6 +576,7 @@ typedef enum {
  	sPerSourcePenalties, sPerSourcePenaltyExemptList,
  	sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile,
  	sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor,
@@ -3323,7 +3325,7 @@ diff --color -ruNp a/servconf.c b/servconf.c
  	sAcceptEnv, sSetEnv, sPermitTunnel,
  	sMatch, sPermitOpen, sPermitListen, sForceCommand, sChrootDirectory,
  	sUsePrivilegeSeparation, sAllowAgentForwarding,
-@@ -643,12 +656,22 @@ static struct {
+@@ -649,12 +662,22 @@ static struct {
  #ifdef GSSAPI
  	{ "gssapiauthentication", sGssAuthentication, SSHCFG_ALL },
  	{ "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL },
@@ -3346,7 +3348,7 @@ diff --color -ruNp a/servconf.c b/servconf.c
  	{ "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL },
  	{ "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL },
  	{ "challengeresponseauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL }, /* alias */
-@@ -1585,6 +1608,10 @@ process_server_config_line_depth(ServerO
+@@ -1605,6 +1628,10 @@ process_server_config_line_depth(ServerO
  		intptr = &options->gss_authentication;
  		goto parse_flag;
  
@@ -3357,7 +3359,7 @@ diff --color -ruNp a/servconf.c b/servconf.c
  	case sGssCleanupCreds:
  		intptr = &options->gss_cleanup_creds;
  		goto parse_flag;
-@@ -1593,6 +1620,22 @@ process_server_config_line_depth(ServerO
+@@ -1613,6 +1640,22 @@ process_server_config_line_depth(ServerO
  		intptr = &options->gss_strict_acceptor;
  		goto parse_flag;
  
@@ -3380,7 +3382,7 @@ diff --color -ruNp a/servconf.c b/servconf.c
  	case sPasswordAuthentication:
  		intptr = &options->password_authentication;
  		goto parse_flag;
-@@ -3178,6 +3221,10 @@ dump_config(ServerOptions *o)
+@@ -3204,6 +3247,10 @@ dump_config(ServerOptions *o)
  #ifdef GSSAPI
  	dump_cfg_fmtint(sGssAuthentication, o->gss_authentication);
  	dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds);
@@ -3392,9 +3394,9 @@ diff --color -ruNp a/servconf.c b/servconf.c
  	dump_cfg_fmtint(sPasswordAuthentication, o->password_authentication);
  	dump_cfg_fmtint(sKbdInteractiveAuthentication,
 diff --color -ruNp a/servconf.h b/servconf.h
---- a/servconf.h	2024-07-01 06:36:28.000000000 +0200
-+++ b/servconf.h	2024-09-16 11:46:34.700940011 +0200
-@@ -149,8 +149,11 @@ typedef struct {
+--- a/servconf.h	2024-09-20 00:20:48.000000000 +0200
++++ b/servconf.h	2026-03-13 12:16:40.004993534 +0100
+@@ -150,8 +150,11 @@ typedef struct {
  	int     kerberos_get_afs_token;		/* If true, try to get AFS token if
  						 * authenticated with Kerberos. */
  	int     gss_authentication;	/* If true, permit GSSAPI authentication */
@@ -3407,8 +3409,8 @@ diff --color -ruNp a/servconf.h b/servconf.h
  						 * authentication. */
  	int     kbd_interactive_authentication;	/* If true, permit */
 diff --color -ruNp a/session.c b/session.c
---- a/session.c	2024-09-16 11:45:56.866133411 +0200
-+++ b/session.c	2024-09-16 11:46:34.701940032 +0200
+--- a/session.c	2026-03-13 12:32:48.472280104 +0100
++++ b/session.c	2026-03-13 12:16:40.005034524 +0100
 @@ -2674,13 +2674,19 @@ do_cleanup(struct ssh *ssh, Authctxt *au
  
  #ifdef KRB5
@@ -3432,9 +3434,9 @@ diff --color -ruNp a/session.c b/session.c
  
  	/* remove agent socket */
 diff --color -ruNp a/ssh.1 b/ssh.1
---- a/ssh.1	2024-09-16 11:45:56.875133603 +0200
-+++ b/ssh.1	2024-09-16 11:46:34.701940032 +0200
-@@ -536,7 +536,13 @@ For full details of the options listed b
+--- a/ssh.1	2026-03-13 12:32:48.479681434 +0100
++++ b/ssh.1	2026-03-13 12:16:40.012217780 +0100
+@@ -538,7 +538,13 @@ For full details of the options listed b
  .It GatewayPorts
  .It GlobalKnownHostsFile
  .It GSSAPIAuthentication
@@ -3448,7 +3450,7 @@ diff --color -ruNp a/ssh.1 b/ssh.1
  .It HashKnownHosts
  .It Host
  .It HostbasedAcceptedAlgorithms
-@@ -624,6 +630,8 @@ flag),
+@@ -626,6 +632,8 @@ flag),
  (supported message integrity codes),
  .Ar kex
  (key exchange algorithms),
@@ -3458,8 +3460,8 @@ diff --color -ruNp a/ssh.1 b/ssh.1
  (key types),
  .Ar key-ca-sign
 diff --color -ruNp a/ssh.c b/ssh.c
---- a/ssh.c	2024-07-01 06:36:28.000000000 +0200
-+++ b/ssh.c	2024-09-16 11:46:34.702940054 +0200
+--- a/ssh.c	2024-09-20 00:20:48.000000000 +0200
++++ b/ssh.c	2026-03-13 12:16:40.012768046 +0100
 @@ -827,6 +827,8 @@ main(int ac, char **av)
  			else if (strcmp(optarg, "kex") == 0 ||
  			    strcasecmp(optarg, "KexAlgorithms") == 0)
@@ -3481,8 +3483,8 @@ diff --color -ruNp a/ssh.c b/ssh.c
  			if (cp == NULL)
  				fatal("Unsupported query \"%s\"", optarg);
 diff --color -ruNp a/ssh_config b/ssh_config
---- a/ssh_config	2024-09-16 11:45:56.884133795 +0200
-+++ b/ssh_config	2024-09-16 11:46:34.702940054 +0200
+--- a/ssh_config	2026-03-13 12:32:48.487976307 +0100
++++ b/ssh_config	2026-03-13 12:16:40.007769377 +0100
 @@ -24,6 +24,8 @@
  #   HostbasedAuthentication no
  #   GSSAPIAuthentication no
@@ -3493,8 +3495,8 @@ diff --color -ruNp a/ssh_config b/ssh_config
  #   CheckHostIP no
  #   AddressFamily any
 diff --color -ruNp a/ssh_config.5 b/ssh_config.5
---- a/ssh_config.5	2024-07-01 06:36:28.000000000 +0200
-+++ b/ssh_config.5	2024-09-16 11:46:34.703940075 +0200
+--- a/ssh_config.5	2024-09-20 00:20:48.000000000 +0200
++++ b/ssh_config.5	2026-03-13 12:16:40.013000257 +0100
 @@ -938,10 +938,68 @@ The default is
  Specifies whether user authentication based on GSSAPI is allowed.
  The default is
@@ -3565,8 +3567,8 @@ diff --color -ruNp a/ssh_config.5 b/ssh_config.5
  Indicates that
  .Xr ssh 1
 diff --color -ruNp a/sshconnect2.c b/sshconnect2.c
---- a/sshconnect2.c	2024-07-01 06:36:28.000000000 +0200
-+++ b/sshconnect2.c	2024-09-16 11:46:34.703940075 +0200
+--- a/sshconnect2.c	2024-09-20 00:20:48.000000000 +0200
++++ b/sshconnect2.c	2026-03-13 12:16:40.008053898 +0100
 @@ -222,6 +222,11 @@ ssh_kex2(struct ssh *ssh, char *host, st
  	char *all_key, *hkalgs = NULL;
  	int r, use_known_hosts_order = 0;
@@ -3669,7 +3671,7 @@ diff --color -ruNp a/sshconnect2.c b/sshconnect2.c
  #ifdef DEBUG_KEXDH
  	/* send 1st encrypted/maced/compressed message */
  	if ((r = sshpkt_start(ssh, SSH2_MSG_IGNORE)) != 0 ||
-@@ -368,6 +439,7 @@ static int input_gssapi_response(int typ
+@@ -369,6 +440,7 @@ static int input_gssapi_response(int typ
  static int input_gssapi_token(int type, u_int32_t, struct ssh *);
  static int input_gssapi_error(int, u_int32_t, struct ssh *);
  static int input_gssapi_errtok(int, u_int32_t, struct ssh *);
@@ -3677,7 +3679,7 @@ diff --color -ruNp a/sshconnect2.c b/sshconnect2.c
  #endif
  
  void	userauth(struct ssh *, char *);
-@@ -384,6 +456,11 @@ static char *authmethods_get(void);
+@@ -385,6 +457,11 @@ static char *authmethods_get(void);
  
  Authmethod authmethods[] = {
  #ifdef GSSAPI
@@ -3689,7 +3691,7 @@ diff --color -ruNp a/sshconnect2.c b/sshconnect2.c
  	{"gssapi-with-mic",
  		userauth_gssapi,
  		userauth_gssapi_cleanup,
-@@ -755,12 +832,32 @@ userauth_gssapi(struct ssh *ssh)
+@@ -756,12 +833,32 @@ userauth_gssapi(struct ssh *ssh)
  	OM_uint32 min;
  	int r, ok = 0;
  	gss_OID mech = NULL;
@@ -3723,7 +3725,7 @@ diff --color -ruNp a/sshconnect2.c b/sshconnect2.c
  
  	/* Check to see whether the mechanism is usable before we offer it */
  	while (authctxt->mech_tried < authctxt->gss_supported_mechs->count &&
-@@ -769,13 +866,15 @@ userauth_gssapi(struct ssh *ssh)
+@@ -770,13 +867,15 @@ userauth_gssapi(struct ssh *ssh)
  		    elements[authctxt->mech_tried];
  		/* My DER encoding requires length<128 */
  		if (mech->length < 128 && ssh_gssapi_check_mechanism(&gssctxt,
@@ -3740,7 +3742,7 @@ diff --color -ruNp a/sshconnect2.c b/sshconnect2.c
  	if (!ok || mech == NULL)
  		return 0;
  
-@@ -1009,6 +1108,55 @@ input_gssapi_error(int type, u_int32_t p
+@@ -1010,6 +1109,55 @@ input_gssapi_error(int type, u_int32_t p
  	free(lang);
  	return r;
  }
@@ -3797,9 +3799,9 @@ diff --color -ruNp a/sshconnect2.c b/sshconnect2.c
  
  static int
 diff --color -ruNp a/sshd.c b/sshd.c
---- a/sshd.c	2024-07-01 06:36:28.000000000 +0200
-+++ b/sshd.c	2024-09-16 11:46:34.704940096 +0200
-@@ -1551,7 +1551,8 @@ main(int ac, char **av)
+--- a/sshd.c	2024-09-20 00:20:48.000000000 +0200
++++ b/sshd.c	2026-03-13 12:16:40.008426802 +0100
+@@ -1558,7 +1558,8 @@ main(int ac, char **av)
  		free(fp);
  	}
  	accumulate_host_timing_secret(cfg, NULL);
@@ -3810,8 +3812,8 @@ diff --color -ruNp a/sshd.c b/sshd.c
  		exit(1);
  	}
 diff --color -ruNp a/sshd_config b/sshd_config
---- a/sshd_config	2024-09-16 11:45:56.888133880 +0200
-+++ b/sshd_config	2024-09-16 11:46:34.704940096 +0200
+--- a/sshd_config	2026-03-13 12:32:48.491841092 +0100
++++ b/sshd_config	2026-03-13 12:16:40.008629209 +0100
 @@ -77,6 +77,8 @@ AuthorizedKeysFile	.ssh/authorized_keys
  # GSSAPI options
  #GSSAPIAuthentication no
@@ -3822,8 +3824,8 @@ diff --color -ruNp a/sshd_config b/sshd_config
  # Set this to 'yes' to enable PAM authentication, account processing,
  # and session processing. If this is enabled, PAM authentication will
 diff --color -ruNp a/sshd_config.5 b/sshd_config.5
---- a/sshd_config.5	2024-09-16 11:45:56.885133816 +0200
-+++ b/sshd_config.5	2024-09-16 11:46:34.704940096 +0200
+--- a/sshd_config.5	2026-03-13 12:32:48.489069461 +0100
++++ b/sshd_config.5	2026-03-13 12:16:40.013495921 +0100
 @@ -739,6 +739,11 @@ Specifies whether to automatically destr
  on logout.
  The default is
@@ -3870,9 +3872,9 @@ diff --color -ruNp a/sshd_config.5 b/sshd_config.5
  Specifies the signature algorithms that will be accepted for hostbased
  authentication as a list of comma-separated patterns.
 diff --color -ruNp a/sshd-session.c b/sshd-session.c
---- a/sshd-session.c	2024-09-16 11:45:56.888133880 +0200
-+++ b/sshd-session.c	2024-09-16 11:46:34.705940118 +0200
-@@ -660,8 +660,8 @@ notify_hostkeys(struct ssh *ssh)
+--- a/sshd-session.c	2026-03-13 12:32:48.491392577 +0100
++++ b/sshd-session.c	2026-03-13 12:16:40.013202390 +0100
+@@ -662,8 +662,8 @@ notify_hostkeys(struct ssh *ssh)
  	}
  	debug3_f("sent %u hostkeys", nkeys);
  	if (nkeys == 0)
@@ -3883,7 +3885,7 @@ diff --color -ruNp a/sshd-session.c b/sshd-session.c
  		sshpkt_fatal(ssh, r, "%s: send", __func__);
  	sshbuf_free(buf);
  }
-@@ -1180,8 +1180,9 @@ main(int ac, char **av)
+@@ -1182,8 +1182,9 @@ main(int ac, char **av)
  			break;
  		}
  	}
@@ -3895,7 +3897,7 @@ diff --color -ruNp a/sshd-session.c b/sshd-session.c
  
  	/* Ensure that umask disallows at least group and world write */
  	new_umask = umask(0077) | 0022;
-@@ -1462,6 +1463,48 @@ do_ssh2_kex(struct ssh *ssh)
+@@ -1476,6 +1477,48 @@ do_ssh2_kex(struct ssh *ssh)
  
  	free(hkalgs);
  
@@ -3944,7 +3946,7 @@ diff --color -ruNp a/sshd-session.c b/sshd-session.c
  	/* start key exchange */
  	if ((r = kex_setup(ssh, myproposal)) != 0)
  		fatal_r(r, "kex_setup");
-@@ -1479,7 +1522,18 @@ do_ssh2_kex(struct ssh *ssh)
+@@ -1493,7 +1536,18 @@ do_ssh2_kex(struct ssh *ssh)
   #ifdef OPENSSL_HAS_ECC
  	kex->kex[KEX_ECDH_SHA2] = kex_gen_server;
   #endif
@@ -3965,8 +3967,8 @@ diff --color -ruNp a/sshd-session.c b/sshd-session.c
  	kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_server;
   	kex->kex[KEX_KEM_MLKEM768X25519_SHA256] = kex_gen_server;
 diff --color -ruNp a/ssh-gss.h b/ssh-gss.h
---- a/ssh-gss.h	2024-07-01 06:36:28.000000000 +0200
-+++ b/ssh-gss.h	2024-09-16 11:46:34.710940224 +0200
+--- a/ssh-gss.h	2024-09-20 00:20:48.000000000 +0200
++++ b/ssh-gss.h	2026-03-13 12:16:40.013453154 +0100
 @@ -61,10 +61,36 @@
  
  #define SSH_GSS_OIDTYPE 0x06
@@ -4092,9 +4094,9 @@ diff --color -ruNp a/ssh-gss.h b/ssh-gss.h
  
  #endif /* _SSH_GSS_H */
 diff --color -ruNp a/sshkey.c b/sshkey.c
---- a/sshkey.c	2024-07-01 06:36:28.000000000 +0200
-+++ b/sshkey.c	2024-09-16 11:46:34.706940139 +0200
-@@ -131,6 +131,75 @@ extern const struct sshkey_impl sshkey_x
+--- a/sshkey.c	2024-09-20 00:20:48.000000000 +0200
++++ b/sshkey.c	2026-03-13 12:16:40.006634461 +0100
+@@ -132,6 +132,75 @@ extern const struct sshkey_impl sshkey_x
  extern const struct sshkey_impl sshkey_xmss_cert_impl;
  #endif
  
@@ -4170,7 +4172,7 @@ diff --color -ruNp a/sshkey.c b/sshkey.c
  const struct sshkey_impl * const keyimpls[] = {
  	&sshkey_ed25519_impl,
  	&sshkey_ed25519_cert_impl,
-@@ -169,6 +238,7 @@ const struct sshkey_impl * const keyimpl
+@@ -170,6 +239,7 @@ const struct sshkey_impl * const keyimpl
  	&sshkey_xmss_impl,
  	&sshkey_xmss_cert_impl,
  #endif
@@ -4178,7 +4180,7 @@ diff --color -ruNp a/sshkey.c b/sshkey.c
  	NULL
  };
  
-@@ -324,7 +394,7 @@ sshkey_alg_list(int certs_only, int plai
+@@ -339,7 +409,7 @@ sshkey_alg_list(int certs_only, int plai
  
  	for (i = 0; keyimpls[i] != NULL; i++) {
  		impl = keyimpls[i];
@@ -4188,9 +4190,9 @@ diff --color -ruNp a/sshkey.c b/sshkey.c
  		if (!include_sigonly && impl->sigonly)
  			continue;
 diff --color -ruNp a/sshkey.h b/sshkey.h
---- a/sshkey.h	2024-07-01 06:36:28.000000000 +0200
-+++ b/sshkey.h	2024-09-16 11:46:34.706940139 +0200
-@@ -71,6 +71,7 @@ enum sshkey_types {
+--- a/sshkey.h	2024-09-20 00:20:48.000000000 +0200
++++ b/sshkey.h	2026-03-13 12:16:40.008972328 +0100
+@@ -73,6 +73,7 @@ enum sshkey_types {
  	KEY_ECDSA_SK_CERT,
  	KEY_ED25519_SK,
  	KEY_ED25519_SK_CERT,

diff --git a/openssh-9.9p1-authorized-keys-principles-option.patch b/openssh-9.9p1-authorized-keys-principles-option.patch
new file mode 100644
index 0000000..9bdd199
--- /dev/null
+++ b/openssh-9.9p1-authorized-keys-principles-option.patch
@@ -0,0 +1,45 @@
+diff --color -ruNp a/auth2-pubkeyfile.c b/auth2-pubkeyfile.c
+--- a/auth2-pubkeyfile.c	2024-09-20 00:20:48.000000000 +0200
++++ b/auth2-pubkeyfile.c	2026-04-09 14:38:41.697178612 +0200
+@@ -50,6 +50,7 @@
+ #include "authfile.h"
+ #include "match.h"
+ #include "ssherr.h"
++#include "xmalloc.h"
+ 
+ int
+ auth_authorise_keyopts(struct passwd *pw, struct sshauthopt *opts,
+@@ -146,20 +147,23 @@ auth_authorise_keyopts(struct passwd *pw
+ static int
+ match_principals_option(const char *principal_list, struct sshkey_cert *cert)
+ {
+-	char *result;
++	char *list, *olist, *entry;
+ 	u_int i;
+ 
+-	/* XXX percent_expand() sequences for authorized_principals? */
+-
+-	for (i = 0; i < cert->nprincipals; i++) {
+-		if ((result = match_list(cert->principals[i],
+-		    principal_list, NULL)) != NULL) {
+-			debug3("matched principal from key options \"%.100s\"",
+-			    result);
+-			free(result);
+-			return 1;
++	olist = list = xstrdup(principal_list);
++	for (;;) {
++		if ((entry = strsep(&list, ",")) == NULL || *entry == '\0')
++			break;
++		for (i = 0; i < cert->nprincipals; i++) {
++			if (strcmp(entry, cert->principals[i]) == 0) {
++				debug3("matched principal from key i"
++				    "options \"%.100s\"", entry);
++				free(olist);
++				return 1;
++			}
+ 		}
+ 	}
++	free(olist);
+ 	return 0;
+ }
+ 

diff --git a/openssh-9.9p1-ecdsa-incomplete-application.patch b/openssh-9.9p1-ecdsa-incomplete-application.patch
new file mode 100644
index 0000000..3b93ca4
--- /dev/null
+++ b/openssh-9.9p1-ecdsa-incomplete-application.patch
@@ -0,0 +1,103 @@
+diff --color -ruNp a/auth2-hostbased.c b/auth2-hostbased.c
+--- a/auth2-hostbased.c	2026-04-09 13:22:28.114045749 +0200
++++ b/auth2-hostbased.c	2026-04-09 14:34:44.876393822 +0200
+@@ -96,9 +96,10 @@ userauth_hostbased(struct ssh *ssh, cons
+ 		error_f("cannot decode key: %s", pkalg);
+ 		goto done;
+ 	}
+-	if (key->type != pktype) {
+-		error_f("type mismatch for decoded key "
+-		    "(received %d, expected %d)", key->type, pktype);
++	if (key->type != pktype || (sshkey_type_plain(pktype) == KEY_ECDSA &&
++	    sshkey_ecdsa_nid_from_name(pkalg) != key->ecdsa_nid)) {
++		error_f("key type mismatch for decoded key "
++		    "(received %s, expected %s)", sshkey_ssh_name(key), pkalg);
+ 		goto done;
+ 	}
+ 	if (match_pattern_list(pkalg, options.hostbased_accepted_algos, 0) != 1) {
+diff --color -ruNp a/auth2-pubkey.c b/auth2-pubkey.c
+--- a/auth2-pubkey.c	2026-04-09 13:22:28.157194118 +0200
++++ b/auth2-pubkey.c	2026-04-09 14:35:48.997689347 +0200
+@@ -152,9 +152,10 @@ userauth_pubkey(struct ssh *ssh, const c
+ 		error_f("cannot decode key: %s", pkalg);
+ 		goto done;
+ 	}
+-	if (key->type != pktype) {
+-		error_f("type mismatch for decoded key "
+-		    "(received %d, expected %d)", key->type, pktype);
++	if (key->type != pktype || (sshkey_type_plain(pktype) == KEY_ECDSA &&
++	    sshkey_ecdsa_nid_from_name(pkalg) != key->ecdsa_nid)) {
++		error_f("key type mismatch for decoded key "
++		    "(received %s, expected %s)", sshkey_ssh_name(key), pkalg);
+ 		goto done;
+ 	}
+ 	if (auth2_key_already_used(authctxt, key)) {
+diff --color -ruNp a/sshconnect2.c b/sshconnect2.c
+--- a/sshconnect2.c	2026-04-09 13:22:28.193412553 +0200
++++ b/sshconnect2.c	2026-04-09 14:42:37.644945762 +0200
+@@ -91,6 +91,7 @@ extern Options options;
+ static char *xxx_host;
+ static struct sockaddr *xxx_hostaddr;
+ static const struct ssh_conn_info *xxx_conn_info;
++static int key_type_allowed(struct sshkey *, const char *);
+ 
+ static int
+ verify_host_key_callback(struct sshkey *hostkey, struct ssh *ssh)
+@@ -100,6 +101,10 @@ verify_host_key_callback(struct sshkey *
+ 	if ((r = sshkey_check_rsa_length(hostkey,
+ 	    options.required_rsa_size)) != 0)
+ 		fatal_r(r, "Bad server host key");
++	if (!key_type_allowed(hostkey, options.hostkeyalgorithms)) {
++		fatal("Server host key %s not in HostKeyAlgorithms",
++		    sshkey_ssh_name(hostkey));
++	}
+ 	if (verify_host_key(xxx_host, xxx_hostaddr, hostkey,
+ 	    xxx_conn_info) != 0)
+ 		fatal("Host key verification failed.");
+@@ -1776,34 +1781,37 @@ load_identity_file(Identity *id)
+ }
+ 
+ static int
+-key_type_allowed_by_config(struct sshkey *key)
++key_type_allowed(struct sshkey *key, const char *allowlist)
+ {
+-	if (match_pattern_list(sshkey_ssh_name(key),
+-	    options.pubkey_accepted_algos, 0) == 1)
++	if (match_pattern_list(sshkey_ssh_name(key), allowlist, 0) == 1)
+ 		return 1;
+ 
+ 	/* RSA keys/certs might be allowed by alternate signature types */
+ 	switch (key->type) {
+ 	case KEY_RSA:
+-		if (match_pattern_list("rsa-sha2-512",
+-		    options.pubkey_accepted_algos, 0) == 1)
++		if (match_pattern_list("rsa-sha2-512", allowlist, 0) == 1)
+ 			return 1;
+-		if (match_pattern_list("rsa-sha2-256",
+-		    options.pubkey_accepted_algos, 0) == 1)
++		if (match_pattern_list("rsa-sha2-256", allowlist, 0) == 1)
+ 			return 1;
+ 		break;
+ 	case KEY_RSA_CERT:
+ 		if (match_pattern_list("rsa-sha2-512-cert-v01@openssh.com",
+-		    options.pubkey_accepted_algos, 0) == 1)
++		    allowlist, 0) == 1)
+ 			return 1;
+ 		if (match_pattern_list("rsa-sha2-256-cert-v01@openssh.com",
+-		    options.pubkey_accepted_algos, 0) == 1)
++		    allowlist, 0) == 1)
+ 			return 1;
+ 		break;
+ 	}
+ 	return 0;
+ }
+ 
++static int
++key_type_allowed_by_config(struct sshkey *key)
++{
++	return key_type_allowed(key, options.pubkey_accepted_algos);
++}
++
+ /* obtain a list of keys from the agent */
+ static int
+ get_agent_identities(struct ssh *ssh, int *agent_fdp,

diff --git a/openssh-9.9p1-fill-default-options-error.patch b/openssh-9.9p1-fill-default-options-error.patch
new file mode 100644
index 0000000..4b80504
--- /dev/null
+++ b/openssh-9.9p1-fill-default-options-error.patch
@@ -0,0 +1,24 @@
+diff --color -ruNp a/readconf.c b/readconf.c
+--- a/readconf.c	2026-04-02 15:36:49.624394836 +0200
++++ b/readconf.c	2026-04-02 15:43:15.115047190 +0200
+@@ -2779,7 +2779,7 @@ fill_default_options(Options * options)
+ {
+ 	char *all_cipher, *all_mac, *all_kex, *all_key, *all_sig;
+ 	char *def_cipher, *def_mac, *def_kex, *def_key, *def_sig;
+-	int ret = 0, r;
++	int ret = 0;
+ 
+ 	if (options->forward_agent == -1)
+ 		options->forward_agent = 0;
+@@ -2989,9 +2989,9 @@ fill_default_options(Options * options)
+ 	    KEX_FIPS_PK_ALG : SSH_ALLOWED_CA_SIGALGS), all_sig);
+ #define ASSEMBLE(what, defaults, all) \
+ 	do { \
+-		if ((r = kex_assemble_names(&options->what, \
++		if ((ret = kex_assemble_names(&options->what, \
+ 		    defaults, all)) != 0) { \
+-			error_fr(r, "%s", #what); \
++			error_fr(ret, "%s", #what); \
+ 			goto fail; \
+ 		} \
+ 	} while (0)

diff --git a/openssh-9.9p1-first-match-wins.patch b/openssh-9.9p1-first-match-wins.patch
new file mode 100644
index 0000000..7d76437
--- /dev/null
+++ b/openssh-9.9p1-first-match-wins.patch
@@ -0,0 +1,106 @@
+diff --color -ruNp a/regress/cfgparse.sh b/regress/cfgparse.sh
+--- a/regress/cfgparse.sh	2024-09-20 00:20:48.000000000 +0200
++++ b/regress/cfgparse.sh	2026-03-05 17:30:54.959690744 +0100
+@@ -51,7 +51,7 @@ listenaddress ::1
+ EOD
+ 
+ ($SUDO ${SSHD} -T -f $OBJ/sshd_config.1 | \
+- grep 'listenaddress ' >$OBJ/sshd_config.2 &&
++ grep '^listenaddress ' >$OBJ/sshd_config.2 &&
+  diff $OBJ/sshd_config.0 $OBJ/sshd_config.2) || \
+  fail "listenaddress order 1"
+ # test 2: listenaddress first
+@@ -67,9 +67,22 @@ listenaddress ::1
+ EOD
+ 
+ ($SUDO ${SSHD} -T -f $OBJ/sshd_config.1 | \
+- grep 'listenaddress ' >$OBJ/sshd_config.2 &&
++ grep '^listenaddress ' >$OBJ/sshd_config.2 &&
+  diff $OBJ/sshd_config.0 $OBJ/sshd_config.2) || \
+  fail "listenaddress order 2"
+ 
++# Check idempotence of MaxStartups
++verbose "maxstartups idempotent"
++echo "maxstartups 1:2:3" > $OBJ/sshd_config.0
++cat > $OBJ/sshd_config.1 <<EOD
++${SSHD_KEYS}
++MaxStartups 1:2:3
++MaxStartups 8:16:32
++EOD
++($SUDO ${SSHD} -T -f $OBJ/sshd_config.1 | \
++ grep '^maxstartups ' >$OBJ/sshd_config.2 &&
++ diff $OBJ/sshd_config.0 $OBJ/sshd_config.2) || \
++ fail "maxstartups idempotence"
++
+ # cleanup
+ rm -f $OBJ/sshd_config.[012]
+diff --color -ruNp a/servconf.c b/servconf.c
+--- a/servconf.c	2026-03-05 16:15:49.035275297 +0100
++++ b/servconf.c	2026-03-05 17:13:29.915897329 +0100
+@@ -1366,7 +1366,7 @@ process_server_config_line_depth(ServerO
+     struct include_list *includes)
+ {
+ 	char *str, ***chararrayptr, **charptr, *arg, *arg2, *p, *keyword;
+-	int cmdline = 0, *intptr, value, value2, n, port, oactive, r;
++	int cmdline = 0, *intptr, value, value2, value3, n, port, oactive, r;
+ 	int ca_only = 0, found = 0;
+ 	SyslogFacility *log_facility_ptr;
+ 	LogLevel *log_level_ptr;
+@@ -2095,25 +2095,27 @@ process_server_config_line_depth(ServerO
+ 		if (!arg || *arg == '\0')
+ 			fatal("%s line %d: %s missing argument.",
+ 			    filename, linenum, keyword);
++		/* begin:rate:max */
+ 		if ((n = sscanf(arg, "%d:%d:%d",
+-		    &options->max_startups_begin,
+-		    &options->max_startups_rate,
+-		    &options->max_startups)) == 3) {
+-			if (options->max_startups_begin >
+-			    options->max_startups ||
+-			    options->max_startups_rate > 100 ||
+-			    options->max_startups_rate < 1)
++		    &value, &value2, &value3)) == 3) {
++			if (value > value3 || value2 > 100 || value2 < 1)
+ 				fatal("%s line %d: Invalid %s spec.",
+ 				    filename, linenum, keyword);
+-		} else if (n != 1)
++		} else if (n == 1) {
++			value3 = value;
++			value = value2 = -1;
++		} else {
+ 			fatal("%s line %d: Invalid %s spec.",
+ 			    filename, linenum, keyword);
+-		else
+-			options->max_startups = options->max_startups_begin;
+-		if (options->max_startups <= 0 ||
+-		    options->max_startups_begin <= 0)
++		}
++		if (value3 <= 0 || (value2 != -1 && value <= 0))
+ 			fatal("%s line %d: Invalid %s spec.",
+ 			    filename, linenum, keyword);
++		if (*activep && options->max_startups == -1) {
++			options->max_startups_begin = value;
++			options->max_startups_rate = value2;
++			options->max_startups = value3;
++		}
+ 		break;
+ 
+ 	case sPerSourceNetBlockSize:
+@@ -2133,7 +2135,7 @@ process_server_config_line_depth(ServerO
+ 		if (n != 1 && n != 2)
+ 			fatal("%s line %d: Invalid %s spec.",
+ 			    filename, linenum, keyword);
+-		if (*activep) {
++		if (*activep && options->per_source_masklen_ipv4 == -1) {
+ 			options->per_source_masklen_ipv4 = value;
+ 			options->per_source_masklen_ipv6 = value2;
+ 		}
+@@ -2621,7 +2623,7 @@ process_server_config_line_depth(ServerO
+ 		else if ((value2 = parse_ipqos(arg)) == -1)
+ 			fatal("%s line %d: Bad %s value: %s",
+ 			    filename, linenum, keyword, arg);
+-		if (*activep) {
++		if (*activep && options->ip_qos_interactive == -1) {
+ 			options->ip_qos_interactive = value;
+ 			options->ip_qos_bulk = value2;
+ 		}

diff --git a/openssh-9.9p1-gsissh.patch b/openssh-9.9p1-gsissh.patch
index 4abbe9e..8abb9e8 100644
--- a/openssh-9.9p1-gsissh.patch
+++ b/openssh-9.9p1-gsissh.patch
@@ -765,8 +765,8 @@ diff -Nur openssh-9.9p1.orig/gss-serv.c openssh-9.9p1/gss-serv.c
  }
 +#endif
  
- 
  /* Extract the client details from a given context. This can only reliably
+  * be called once for a context */
 @@ -394,21 +428,24 @@
  	gss_buffer_desc ename = GSS_C_EMPTY_BUFFER;
  
@@ -923,7 +923,7 @@ diff -Nur openssh-9.9p1.orig/gss-serv.c openssh-9.9p1/gss-serv.c
 +			gss_release_name(&lmin, &gssapi_client.ctx_name);
  
  			if (gssapi_client.indicators != NULL) {
- 				for(i = 0; gssapi_client.indicators[i] != NULL; i++) {
+ 				for (i = 0; gssapi_client.indicators[i] != NULL; i++)
 @@ -579,6 +649,24 @@
  	return (0);
  }
@@ -1863,9 +1863,9 @@ diff -Nur openssh-9.9p1.orig/servconf.c openssh-9.9p1/servconf.c
  	options->gss_deleg_creds = -1;
  	options->gss_strict_acceptor = -1;
 +	options->gsi_allow_limited_proxy = -1;
+ 	options->gss_indicators = NULL;
  	options->gss_store_rekey = -1;
  	options->gss_kex_algorithms = NULL;
- 	options->gss_indicators = NULL;
 @@ -317,6 +319,8 @@
  		options->use_pam = 0;
  	if (options->pam_service_name == NULL)

diff --git a/openssh-9.9p1-maxstartups-mistracking.patch b/openssh-9.9p1-maxstartups-mistracking.patch
new file mode 100644
index 0000000..0e92903
--- /dev/null
+++ b/openssh-9.9p1-maxstartups-mistracking.patch
@@ -0,0 +1,73 @@
+diff --color -ruNp a/srclimit.c b/srclimit.c
+--- a/srclimit.c	2024-09-20 00:20:48.000000000 +0200
++++ b/srclimit.c	2026-03-06 13:30:48.408309619 +0100
+@@ -427,7 +427,9 @@ srclimit_penalise(struct xaddr *addr, in
+ 			penalty->active = 1;
+ 		if (RB_INSERT(penalties_by_expiry, by_expiry, penalty) != NULL)
+ 			fatal_f("internal error: %s penalty tables corrupt", t);
+-		verbose_f("%s: new %s %s penalty of %d seconds for %s", t,
++		do_log2_f(penalty->active ?
++		    SYSLOG_LEVEL_INFO : SYSLOG_LEVEL_VERBOSE,
++		    "%s: new %s %s penalty of %d seconds for %s", t,
+ 		    addrnetmask, penalty->active ? "active" : "deferred",
+ 		    penalty_secs, reason);
+ 		if (++(*npenaltiesp) > (size_t)max_sources)
+@@ -446,7 +448,7 @@ srclimit_penalise(struct xaddr *addr, in
+ 		existing->expiry = now + penalty_cfg.penalty_max;
+ 	if (existing->expiry - now > penalty_cfg.penalty_min &&
+ 	    !existing->active) {
+-		verbose_f("%s: activating %s penalty of %lld seconds for %s",
++		logit_f("%s: activating %s penalty of %lld seconds for %s",
+ 		    addrnetmask, t, (long long)(existing->expiry - now),
+ 		    reason);
+ 		existing->active = 1;
+diff --color -ruNp a/sshd.c b/sshd.c
+--- a/sshd.c	2026-03-06 13:10:52.653617548 +0100
++++ b/sshd.c	2026-03-06 13:24:50.865079998 +0100
+@@ -291,8 +291,10 @@ child_finish(struct early_child *child)
+ {
+ 	if (children_active == 0)
+ 		fatal_f("internal error: children_active underflow");
+-	if (child->pipefd != -1)
++	if (child->pipefd != -1) {
++		srclimit_done(child->pipefd);
+ 		close(child->pipefd);
++	}
+ 	free(child->id);
+ 	memset(child, '\0', sizeof(*child));
+ 	child->pipefd = -1;
+@@ -311,6 +313,7 @@ child_close(struct early_child *child, i
+ 	if (!quiet)
+ 		debug_f("enter%s", force_final ? " (forcing)" : "");
+ 	if (child->pipefd != -1) {
++		srclimit_done(child->pipefd);
+ 		close(child->pipefd);
+ 		child->pipefd = -1;
+ 	}
+@@ -978,10 +981,11 @@ server_accept_loop(int *sock_in, int *so
+ 				}
+ 				/* FALLTHROUGH */
+ 			case 0:
+-				/* child exited preauth */
++				/* child closed pipe */
+ 				if (children[i].early)
+ 					listening--;
+-				srclimit_done(children[i].pipefd);
++				debug3_f("child %lu for %s closed pipe",
++				    (long)children[i].pid, children[i].id);
+ 				child_close(&(children[i]), 0, 0);
+ 				break;
+ 			case 1:
+@@ -1003,6 +1007,12 @@ server_accept_loop(int *sock_in, int *so
+ 					    "child %ld for %s in state %d",
+ 					    (int)c, (long)children[i].pid,
+ 					    children[i].id, children[i].early);
++
++					if (children[i].early)
++						listening--;
++					if (children[i].pid > 0)
++						kill(children[i].pid, SIGTERM);
++					child_close(&(children[i]), 0, 0);
+ 				}
+ 				break;
+ 			}

diff --git a/openssh-9.9p1-mux-askpass-check.patch b/openssh-9.9p1-mux-askpass-check.patch
new file mode 100644
index 0000000..2176243
--- /dev/null
+++ b/openssh-9.9p1-mux-askpass-check.patch
@@ -0,0 +1,20 @@
+diff --color -ruNp a/mux.c b/mux.c
+--- a/mux.c	2024-09-20 00:20:48.000000000 +0200
++++ b/mux.c	2026-04-09 15:02:36.016198814 +0200
+@@ -1137,6 +1137,16 @@ mux_master_process_proxy(struct ssh *ssh
+ 
+ 	debug_f("channel %d: proxy request", c->self);
+ 
++	if (options.control_master == SSHCTL_MASTER_ASK ||
++	    options.control_master == SSHCTL_MASTER_AUTO_ASK) {
++		if (!ask_permission("Allow multiplex proxy connection?")) {
++			debug2_f("proxy refused by user");
++			reply_error(reply, MUX_S_PERMISSION_DENIED, rid,
++			    "Permission denied");
++			return 0;
++		}
++	}
++
+ 	c->mux_rcb = channel_proxy_downstream;
+ 	if ((r = sshbuf_put_u32(reply, MUX_S_PROXY)) != 0 ||
+ 	    (r = sshbuf_put_u32(reply, rid)) != 0)

diff --git a/openssh-9.9p1-proxyjump-username-validity-checks.patch b/openssh-9.9p1-proxyjump-username-validity-checks.patch
new file mode 100644
index 0000000..c6ee415
--- /dev/null
+++ b/openssh-9.9p1-proxyjump-username-validity-checks.patch
@@ -0,0 +1,402 @@
+diff --color -ruNp a/readconf.c b/readconf.c
+--- a/readconf.c	2026-04-10 15:42:50.693725820 +0200
++++ b/readconf.c	2026-04-10 15:49:57.441110287 +0200
+@@ -1533,9 +1533,6 @@ parse_char_array:
+ 
+ 	case oProxyCommand:
+ 		charptr = &options->proxy_command;
+-		/* Ignore ProxyCommand if ProxyJump already specified */
+-		if (options->jump_host != NULL)
+-			charptr = &options->jump_host; /* Skip below */
+ parse_command:
+ 		if (str == NULL) {
+ 			error("%.200s line %d: Missing argument.",
+@@ -1556,7 +1553,7 @@ parse_command:
+ 		}
+ 		len = strspn(str, WHITESPACE "=");
+ 		/* XXX use argv? */
+-		if (parse_jump(str + len, options, *activep) == -1) {
++		if (parse_jump(str + len, options, cmdline, *activep) == -1) {
+ 			error("%.200s line %d: Invalid ProxyJump \"%s\"",
+ 			    filename, linenum, str + len);
+ 			goto out;
+@@ -3370,65 +3367,116 @@ parse_forward(struct Forward *fwd, const
+ }
+ 
+ int
+-parse_jump(const char *s, Options *o, int active)
++ssh_valid_hostname(const char *s)
+ {
+-	char *orig, *sdup, *cp;
+-	char *host = NULL, *user = NULL;
+-	int r, ret = -1, port = -1, first;
++	size_t i;
+ 
+-	active &= o->proxy_command == NULL && o->jump_host == NULL;
++	if (*s == '-')
++		return 0;
++	for (i = 0; s[i] != 0; i++) {
++		if (strchr("'`\"$\\;&<>|(){},", s[i]) != NULL ||
++		    isspace((u_char)s[i]) || iscntrl((u_char)s[i]))
++			return 0;
++	}
++	return 1;
++}
+ 
+-	orig = sdup = xstrdup(s);
++int
++ssh_valid_ruser(const char *s)
++{
++	size_t i;
++
++	if (*s == '-')
++		return 0;
++	for (i = 0; s[i] != 0; i++) {
++		if (iscntrl((u_char)s[i]))
++			return 0;
++		if (strchr("'`\";&<>|(){}", s[i]) != NULL)
++			return 0;
++		/* Disallow '-' after whitespace */
++		if (isspace((u_char)s[i]) && s[i + 1] == '-')
++			return 0;
++		/* Disallow \ in last position */
++		if (s[i] == '\\' && s[i + 1] == '\0')
++			return 0;
++	}
++	return 1;
++}
++
++int
++parse_jump(const char *s, Options *o, int strict, int active)
++{
++	char *orig = NULL, *sdup = NULL, *cp;
++	char *tmp_user = NULL, *tmp_host = NULL, *host = NULL, *user = NULL;
++	int r, ret = -1, tmp_port = -1, port = -1, first = 1;
++
++	if (strcasecmp(s, "none") == 0) {
++		if (active && o->jump_host == NULL) {
++			o->jump_host = xstrdup("none");
++			o->jump_port = 0;
++		}
++		return 0;
++	}
+ 
+-	/* Remove comment and trailing whitespace */
++	orig = xstrdup(s);
+ 	if ((cp = strchr(orig, '#')) != NULL)
+ 		*cp = '\0';
+ 	rtrim(orig);
+ 
+-	first = active;
++	active &= o->proxy_command == NULL && o->jump_host == NULL;
++	sdup = xstrdup(orig);
+ 	do {
+-		if (strcasecmp(s, "none") == 0)
+-			break;
++		/* Work backwards through string */
+ 		if ((cp = strrchr(sdup, ',')) == NULL)
+ 			cp = sdup; /* last */
+ 		else
+ 			*cp++ = '\0';
+ 
+-		if (first) {
+-			/* First argument and configuration is active */
+-			r = parse_ssh_uri(cp, &user, &host, &port);
+-			if (r == -1 || (r == 1 &&
+-			    parse_user_host_port(cp, &user, &host, &port) != 0))
++		r = parse_ssh_uri(cp, &tmp_user, &tmp_host, &tmp_port);
++		if (r == -1 || (r == 1 && parse_user_host_port(cp,
++		    &tmp_user, &tmp_host, &tmp_port) != 0))
++			goto out; /* error already logged */
++		if (strict) {
++			if (!ssh_valid_hostname(tmp_host)) {
++				error_f("invalid hostname \"%s\"", tmp_host);
+ 				goto out;
+-		} else {
+-			/* Subsequent argument or inactive configuration */
+-			r = parse_ssh_uri(cp, NULL, NULL, NULL);
+-			if (r == -1 || (r == 1 &&
+-			    parse_user_host_port(cp, NULL, NULL, NULL) != 0))
++			}
++			if (tmp_user != NULL && !ssh_valid_ruser(tmp_user)) {
++				error_f("invalid username \"%s\"", tmp_user);
+ 				goto out;
++			}
++		}
++		if (first) {
++			user = tmp_user;
++			host = tmp_host;
++			port = tmp_port;
++			tmp_user = tmp_host = NULL; /* transferred */
+ 		}
+ 		first = 0; /* only check syntax for subsequent hosts */
++		free(tmp_user);
++		free(tmp_host);
++		tmp_user = tmp_host = NULL;
++		tmp_port = -1;
+ 	} while (cp != sdup);
++
+ 	/* success */
+ 	if (active) {
+-		if (strcasecmp(s, "none") == 0) {
+-			o->jump_host = xstrdup("none");
+-			o->jump_port = 0;
+-		} else {
+-			o->jump_user = user;
+-			o->jump_host = host;
+-			o->jump_port = port;
+-			o->proxy_command = xstrdup("none");
+-			user = host = NULL;
+-			if ((cp = strrchr(s, ',')) != NULL && cp != s) {
+-				o->jump_extra = xstrdup(s);
+-				o->jump_extra[cp - s] = '\0';
+-			}
++		o->jump_user = user;
++		o->jump_host = host;
++		o->jump_port = port;
++		o->proxy_command = xstrdup("none");
++		user = host = NULL; /* transferred */
++		if (orig != NULL && (cp = strrchr(orig, ',')) != NULL) {
++			o->jump_extra = xstrdup(orig);
++			o->jump_extra[cp - orig] = '\0';
+ 		}
+ 	}
+ 	ret = 0;
+  out:
+ 	free(orig);
++	free(sdup);
++	free(tmp_user);
++	free(tmp_host);
+ 	free(user);
+ 	free(host);
+ 	return ret;
+diff --color -ruNp a/readconf.h b/readconf.h
+--- a/readconf.h	2026-04-10 15:42:50.470697714 +0200
++++ b/readconf.h	2026-04-10 15:49:57.442110306 +0200
+@@ -249,7 +249,9 @@ int	 process_config_line(Options *, stru
+ int	 read_config_file(const char *, struct passwd *, const char *,
+     const char *, Options *, int, int *);
+ int	 parse_forward(struct Forward *, const char *, int, int);
+-int	 parse_jump(const char *, Options *, int);
++int	 ssh_valid_hostname(const char *);
++int	 ssh_valid_ruser(const char *);
++int	 parse_jump(const char *, Options *, int, int);
+ int	 parse_ssh_uri(const char *, char **, char **, int *);
+ int	 default_ssh_port(void);
+ int	 option_clear_or_none(const char *);
+diff --color -ruNp a/regress/Makefile b/regress/Makefile
+--- a/regress/Makefile	2026-04-10 15:42:50.533815702 +0200
++++ b/regress/Makefile	2026-04-10 16:07:30.566094450 +0200
+@@ -111,7 +111,8 @@ LTESTS= 	connect \
+ 		agent-pkcs11-restrict \
+ 		agent-pkcs11-cert \
+ 		penalty \
+-		penalty-expire
++		penalty-expire \
++		proxyjump
+ 
+ INTEROP_TESTS=	putty-transfer putty-ciphers putty-kex conch-ciphers
+ INTEROP_TESTS+=	dropbear-ciphers dropbear-kex
+diff --color -ruNp a/regress/proxyjump.sh b/regress/proxyjump.sh
+--- a/regress/proxyjump.sh	1970-01-01 01:00:00.000000000 +0100
++++ b/regress/proxyjump.sh	2026-04-10 16:07:55.225958206 +0200
+@@ -0,0 +1,102 @@
++#	$OpenBSD: proxyjump.sh,v 1.1 2026/03/30 07:19:02 djm Exp $
++#	Placed in the Public Domain.
++
++tid="proxyjump"
++
++# Parsing tests
++verbose "basic parsing"
++for jspec in \
++	"jump1" \
++	"user@jump1" \
++	"jump1:2222" \
++	"user@jump1:2222" \
++	"jump1,jump2" \
++	"user1@jump1:2221,user2@jump2:2222" \
++	"ssh://user@host:2223" \
++	; do
++	case "$jspec" in
++	"jump1")		expected="jump1" ;;
++	"user@jump1")		expected="user@jump1" ;;
++	"jump1:2222")		expected="jump1:2222" ;;
++	"user@jump1:2222")	expected="user@jump1:2222" ;;
++	"jump1,jump2")		expected="jump1,jump2" ;;
++	"user1@jump1:2221,user2@jump2:2222")
++		expected="user1@jump1:2221,user2@jump2:2222" ;;
++	"ssh://user@host:2223")	expected="user@host:2223" ;;
++	esac
++	f=`${SSH} -GF /dev/null -oProxyJump="$jspec" somehost | \
++		awk '/^proxyjump /{print $2}'`
++	if [ "$f" != "$expected" ]; then
++		fail "ProxyJump $jspec: expected $expected, got $f"
++	fi
++	f=`${SSH} -GF /dev/null -J "$jspec" somehost | \
++		awk '/^proxyjump /{print $2}'`
++	if [ "$f" != "$expected" ]; then
++		fail "ssh -J $jspec: expected $expected, got $f"
++	fi
++done
++
++verbose "precedence"
++f=`${SSH} -GF /dev/null -oProxyJump=none -oProxyJump=jump1 somehost | \
++	grep "^proxyjump "`
++if [ -n "$f" ]; then
++	fail "ProxyJump=none first did not win"
++fi
++f=`${SSH} -GF /dev/null -oProxyJump=jump -oProxyCommand=foo somehost | \
++	grep "^proxyjump "`
++if [ "$f" != "proxyjump jump" ]; then
++	fail "ProxyJump first did not win over ProxyCommand"
++fi
++f=`${SSH} -GF /dev/null -oProxyCommand=foo -oProxyJump=jump somehost | \
++	grep "^proxycommand "`
++if [ "$f" != "proxycommand foo" ]; then
++	fail "ProxyCommand first did not win over ProxyJump"
++fi
++
++verbose "command-line -J invalid characters"
++cp $OBJ/ssh_config $OBJ/ssh_config.orig
++for jspec in \
++	"host;with;semicolon" \
++	"host'with'quote" \
++	"host\`with\`backtick" \
++	"host\$with\$dollar" \
++	"host(with)brace" \
++	"user;with;semicolon@host" \
++	"user'with'quote@host" \
++	"user\`with\`backtick@host" \
++	"user(with)brace@host" ; do
++	${SSH} -GF /dev/null -J "$jspec" somehost >/dev/null 2>&1
++	if [ $? -ne 255 ]; then
++		fail "ssh -J \"$jspec\" was not rejected"
++	fi
++	${SSH} -GF /dev/null -oProxyJump="$jspec" somehost >/dev/null 2>&1
++	if [ $? -ne 255 ]; then
++		fail "ssh -oProxyJump=\"$jspec\" was not rejected"
++	fi
++done
++# Special characters should be accepted in the config though.
++echo "ProxyJump user;with;semicolon@host;with;semicolon" >> $OBJ/ssh_config
++f=`${SSH} -GF $OBJ/ssh_config somehost | grep "^proxyjump "`
++if [ "$f" != "proxyjump user;with;semicolon@host;with;semicolon" ]; then
++	fail "ProxyJump did not allow special characters in config: $f"
++fi
++
++verbose "functional test"
++# Use different names to avoid the loop detection in ssh.c
++grep -iv HostKeyAlias $OBJ/ssh_config.orig > $OBJ/ssh_config
++cat << _EOF >> $OBJ/ssh_config
++Host jump-host
++	HostkeyAlias jump-host
++Host target-host
++	HostkeyAlias target-host
++_EOF
++cp $OBJ/known_hosts $OBJ/known_hosts.orig
++sed 's/^[^ ]* /jump-host /' < $OBJ/known_hosts.orig > $OBJ/known_hosts
++sed 's/^[^ ]* /target-host /' < $OBJ/known_hosts.orig >> $OBJ/known_hosts
++start_sshd
++
++verbose "functional ProxyJump"
++res=`${REAL_SSH} -F $OBJ/ssh_config -J jump-host target-host echo "SUCCESS" 2>/dev/null`
++if [ "$res" != "SUCCESS" ]; then
++	fail "functional test failed: expected SUCCESS, got $res"
++fi
+diff --color -ruNp a/ssh.c b/ssh.c
+--- a/ssh.c	2026-04-10 15:42:50.657913189 +0200
++++ b/ssh.c	2026-04-10 16:04:07.489047966 +0200
+@@ -639,43 +639,6 @@ ssh_conn_info_free(struct ssh_conn_info
+ 	free(cinfo);
+ }
+ 
+-static int
+-valid_hostname(const char *s)
+-{
+-	size_t i;
+-
+-	if (*s == '-')
+-		return 0;
+-	for (i = 0; s[i] != 0; i++) {
+-		if (strchr("'`\"$\\;&<>|(){}", s[i]) != NULL ||
+-		    isspace((u_char)s[i]) || iscntrl((u_char)s[i]))
+-			return 0;
+-	}
+-	return 1;
+-}
+-
+-static int
+-valid_ruser(const char *s)
+-{
+-	size_t i;
+-
+-	if (*s == '-')
+-		return 0;
+-	for (i = 0; s[i] != 0; i++) {
+-		if (iscntrl((u_char)s[i]))
+-			return 0;
+-		if (strchr("'`\";&<>|(){}", s[i]) != NULL)
+-			return 0;
+-		/* Disallow '-' after whitespace */
+-		if (isspace((u_char)s[i]) && s[i + 1] == '-')
+-			return 0;
+-		/* Disallow \ in last position */
+-		if (s[i] == '\\' && s[i + 1] == '\0')
+-			return 0;
+-	}
+-	return 1;
+-}
+-
+ /*
+  * Main program for the ssh client.
+  */
+@@ -931,9 +894,9 @@ main(int ac, char **av)
+ 			}
+ 			if (options.proxy_command != NULL)
+ 				fatal("Cannot specify -J with ProxyCommand");
+-			if (parse_jump(optarg, &options, 1) == -1)
++			if (parse_jump(optarg, &options, 1, 1) == -1)
++
+ 				fatal("Invalid -J argument");
+-			options.proxy_command = xstrdup("none");
+ 			break;
+ 		case 't':
+ 			if (options.request_tty == REQUEST_TTY_YES)
+@@ -1183,10 +1146,15 @@ main(int ac, char **av)
+ 	if (!host)
+ 		usage();
+ 
+-	if (!valid_hostname(host))
+-		fatal("hostname contains invalid characters");
+-	if (options.user != NULL && !valid_ruser(options.user))
++	/*
++	 * Validate commandline-specified values that end up in %tokens
++	 * before they are used in config parsing.
++	 */
++	if (options.user != NULL && !ssh_valid_ruser(options.user))
+ 		fatal("remote username contains invalid characters");
++	if (!ssh_valid_hostname(host))
++		fatal("hostname contains invalid characters");
++
+ 	options.host_arg = xstrdup(host);
+ 
+ 	/* Initialize the command to execute on remote host. */
+@@ -1347,7 +1315,8 @@ main(int ac, char **av)
+ 			sshbin = "ssh";
+ 
+ 		/* Consistency check */
+-		if (options.proxy_command != NULL)
++		if (options.proxy_command != NULL &&
++		    strcasecmp(options.proxy_command, "none") != 0)
+ 			fatal("inconsistent options: ProxyCommand+ProxyJump");
+ 		/* Never use FD passing for ProxyJump */
+ 		options.proxy_use_fdpass = 0;
+@@ -1467,7 +1436,7 @@ main(int ac, char **av)
+ 	cinfo->jmphost = xstrdup(options.jump_host == NULL ?
+ 	    "" : options.jump_host);
+ 
+-	if (user_on_commandline && !valid_ruser(options.user))
++	if (user_on_commandline && !ssh_valid_ruser(options.user))
+ 		fatal("remote username contains invalid characters");
+ 
+ 	cinfo->conn_hash_hex = ssh_connection_hash(cinfo->thishost,

diff --git a/openssh-9.9p1-scp-clear-setuid.patch b/openssh-9.9p1-scp-clear-setuid.patch
new file mode 100644
index 0000000..1a848a1
--- /dev/null
+++ b/openssh-9.9p1-scp-clear-setuid.patch
@@ -0,0 +1,15 @@
+diff --color -ruNp a/scp.c b/scp.c
+--- a/scp.c	2026-04-07 15:54:11.193730842 +0200
++++ b/scp.c	2026-04-07 15:55:52.529425481 +0200
+@@ -1705,8 +1705,10 @@ sink(int argc, char **argv, const char *
+ 
+ 	setimes = targisdir = 0;
+ 	mask = umask(0);
+-	if (!pflag)
++	if (!pflag) {
++		mask |= 07000;
+ 		(void) umask(mask);
++	}
+ 	if (argc != 1) {
+ 		run_err("ambiguous target");
+ 		exit(1);

diff --git a/openssh-9.9p1-sshd-no-delegate-credentials.patch b/openssh-9.9p1-sshd-no-delegate-credentials.patch
index 2b70103..59d0120 100644
--- a/openssh-9.9p1-sshd-no-delegate-credentials.patch
+++ b/openssh-9.9p1-sshd-no-delegate-credentials.patch
@@ -1,8 +1,7 @@
-diff --git a/gss-serv.c b/gss-serv.c
-index 5c0491cf1..e2c501d0c 100644
---- a/gss-serv.c
-+++ b/gss-serv.c
-@@ -509,6 +509,11 @@ ssh_gssapi_cleanup_creds(void)
+diff --color -ruNp a/gss-serv.c b/gss-serv.c
+--- a/gss-serv.c	2026-03-11 13:54:53.076924823 +0100
++++ b/gss-serv.c	2026-03-11 14:10:41.232855086 +0100
+@@ -493,6 +493,11 @@ ssh_gssapi_cleanup_creds(void)
  int
  ssh_gssapi_storecreds(void)
  {
@@ -14,19 +13,18 @@ index 5c0491cf1..e2c501d0c 100644
  	if (gssapi_client.mech && gssapi_client.mech->storecreds) {
  		return (*gssapi_client.mech->storecreds)(&gssapi_client);
  	} else
-diff --git a/servconf.c b/servconf.c
-index aab653244..02a9888c9 100644
---- a/servconf.c
-+++ b/servconf.c
-@@ -144,6 +144,7 @@ initialize_server_options(ServerOptions *options)
+diff --color -ruNp a/servconf.c b/servconf.c
+--- a/servconf.c	2026-03-11 13:54:53.086263187 +0100
++++ b/servconf.c	2026-03-11 14:03:10.708713524 +0100
+@@ -143,6 +143,7 @@ initialize_server_options(ServerOptions
  	options->gss_authentication=-1;
  	options->gss_keyex = -1;
  	options->gss_cleanup_creds = -1;
 +	options->gss_deleg_creds = -1;
  	options->gss_strict_acceptor = -1;
+ 	options->gss_indicators = NULL;
  	options->gss_store_rekey = -1;
- 	options->gss_kex_algorithms = NULL;
-@@ -403,6 +404,8 @@ fill_default_server_options(ServerOptions *options)
+@@ -402,6 +403,8 @@ fill_default_server_options(ServerOption
  		options->gss_keyex = 0;
  	if (options->gss_cleanup_creds == -1)
  		options->gss_cleanup_creds = 1;
@@ -61,7 +59,7 @@ index aab653244..02a9888c9 100644
  	{ "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL },
  	{ "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL },
  	{ "gssapistorecredentialsonrekey", sUnsupported, SSHCFG_GLOBAL },
-@@ -1713,6 +1719,10 @@ process_server_config_line_depth(ServerOptions *options, char *line,
+@@ -1703,6 +1709,10 @@ process_server_config_line_depth(ServerO
  		intptr = &options->gss_cleanup_creds;
  		goto parse_flag;
  
@@ -72,7 +70,7 @@ index aab653244..02a9888c9 100644
  	case sGssStrictAcceptor:
  		intptr = &options->gss_strict_acceptor;
  		goto parse_flag;
-@@ -3359,6 +3369,7 @@ dump_config(ServerOptions *o)
+@@ -3348,6 +3358,7 @@ dump_config(ServerOptions *o)
  #ifdef GSSAPI
  	dump_cfg_fmtint(sGssAuthentication, o->gss_authentication);
  	dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds);
@@ -80,10 +78,9 @@ index aab653244..02a9888c9 100644
  	dump_cfg_fmtint(sGssKeyEx, o->gss_keyex);
  	dump_cfg_fmtint(sGssStrictAcceptor, o->gss_strict_acceptor);
  	dump_cfg_fmtint(sGssStoreRekey, o->gss_store_rekey);
-diff --git a/servconf.h b/servconf.h
-index 7c41df417..6bfdf6305 100644
---- a/servconf.h
-+++ b/servconf.h
+diff --color -ruNp a/servconf.h b/servconf.h
+--- a/servconf.h	2026-03-11 13:54:53.086763709 +0100
++++ b/servconf.h	2026-03-11 14:13:51.130708769 +0100
 @@ -158,6 +158,7 @@ typedef struct {
  	int     gss_authentication;	/* If true, permit GSSAPI authentication */
  	int     gss_keyex;		/* If true, permit GSSAPI key exchange */
@@ -92,11 +89,10 @@ index 7c41df417..6bfdf6305 100644
  	int     gss_strict_acceptor;	/* If true, restrict the GSSAPI acceptor name */
  	int 	gss_store_rekey;
  	char   *gss_kex_algorithms;	/* GSSAPI kex methods to be offered by client. */
-diff --git a/sshd_config.0 b/sshd_config.0
-index 49349bb30..e798f4df5 100644
---- a/sshd_config.0
-+++ b/sshd_config.0
-@@ -453,6 +453,9 @@ DESCRIPTION
+diff --color -ruNp a/sshd_config.0 b/sshd_config.0
+--- a/sshd_config.0	2026-03-11 13:54:52.904233471 +0100
++++ b/sshd_config.0	2026-03-11 14:12:35.341170737 +0100
+@@ -451,6 +451,9 @@ DESCRIPTION
               Specifies whether to automatically destroy the user's credentials
               cache on logout.  The default is yes.
  
@@ -106,11 +102,10 @@ index 49349bb30..e798f4df5 100644
       GSSAPIStrictAcceptorCheck
               Determines whether to be strict about the identity of the GSSAPI
               acceptor a client authenticates against.  If set to yes then the
-diff --git a/sshd_config.5 b/sshd_config.5
-index 90ab87edd..8c677bfd0 100644
---- a/sshd_config.5
-+++ b/sshd_config.5
-@@ -733,6 +733,9 @@ Specifies whether to automatically destroy the user's credentials cache
+diff --color -ruNp a/sshd_config.5 b/sshd_config.5
+--- a/sshd_config.5	2026-03-11 13:54:53.087046352 +0100
++++ b/sshd_config.5	2026-03-11 14:05:15.657248031 +0100
+@@ -733,6 +733,9 @@ Specifies whether to automatically destr
  on logout.
  The default is
  .Cm yes .

diff --git a/openssh-9.9p1-support-authentication-indicators-in-GSSAPI.patch b/openssh-9.9p1-support-authentication-indicators-in-GSSAPI.patch
index 237e45d..6c55a66 100644
--- a/openssh-9.9p1-support-authentication-indicators-in-GSSAPI.patch
+++ b/openssh-9.9p1-support-authentication-indicators-in-GSSAPI.patch
@@ -1,38 +1,7 @@
-From 5d5a66e96ad03132f65371070f4fa475f10207d9 Mon Sep 17 00:00:00 2001
-From: Alexander Bokovoy <abokovoy@redhat.com>
-Date: Mon, 10 Jun 2024 23:00:03 +0300
-Subject: [PATCH] support authentication indicators in GSSAPI
-
-RFC 6680 defines a set of GSSAPI extensions to handle attributes
-associated with the GSSAPI names. MIT Kerberos and FreeIPA use
-name attributes to add information about pre-authentication methods used
-to acquire the initial Kerberos ticket. The attribute 'auth-indicators'
-may contain list of strings that KDC has associated with the ticket
-issuance process.
-
-Use authentication indicators to authorise or deny access to SSH server.
-GSSAPIIndicators setting allows to specify a list of possible indicators
-that a Kerberos ticket presented must or must not contain. More details
-on the syntax are provided in sshd_config(5) man page.
-
-Fixes: https://bugzilla.mindrot.org/show_bug.cgi?id=2696
-
-Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
----
- configure.ac    |   1 +
- gss-serv-krb5.c |  64 +++++++++++++++++++++++++++---
- gss-serv.c      | 103 +++++++++++++++++++++++++++++++++++++++++++++++-
- servconf.c      |  15 ++++++-
- servconf.h      |   2 +
- ssh-gss.h       |   7 ++++
- sshd_config.5   |  44 +++++++++++++++++++++
- 7 files changed, 228 insertions(+), 8 deletions(-)
-
-diff --git a/configure.ac b/configure.ac
-index d92a85809..2cbe20bf3 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -5004,6 +5004,7 @@ AC_ARG_WITH([kerberos5],
+diff --color -ruNp a/configure.ac b/configure.ac
+--- a/configure.ac	2026-03-10 12:43:36.860784813 +0100
++++ b/configure.ac	2026-03-10 12:46:27.022297835 +0100
+@@ -4932,6 +4932,7 @@ AC_ARG_WITH([kerberos5],
  		AC_CHECK_HEADERS([gssapi.h gssapi/gssapi.h])
  		AC_CHECK_HEADERS([gssapi_krb5.h gssapi/gssapi_krb5.h])
  		AC_CHECK_HEADERS([gssapi_generic.h gssapi/gssapi_generic.h])
@@ -40,113 +9,10 @@ index d92a85809..2cbe20bf3 100644
  
  		AC_SEARCH_LIBS([k_hasafs], [kafs], [AC_DEFINE([USE_AFS], [1],
  			[Define this if you want to use libkafs' AFS support])])
-diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c
-index 03188d9b3..2c786ef14 100644
---- a/gss-serv-krb5.c
-+++ b/gss-serv-krb5.c
-@@ -43,6 +43,7 @@
- #include "log.h"
- #include "misc.h"
- #include "servconf.h"
-+#include "match.h"
- 
- #include "ssh-gss.h"
- 
-@@ -87,6 +88,32 @@ ssh_gssapi_krb5_init(void)
- 	return 1;
- }
- 
-+/* Check if any of the indicators in the Kerberos ticket match
-+ * 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
-+ */
-+
-+static int
-+ssh_gssapi_check_indicators(ssh_gssapi_client *client, int *matched)
-+{
-+	int ret;
-+	u_int i;
-+
-+	/* 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) {
-+			*matched = i;
-+			return ret;
-+		}
-+	}
-+	/* No rule matched */
-+	return 0;
-+}
-+
- /* Check if this user is OK to login. This only works with krb5 - other
-  * GSSAPI mechanisms will need their own.
-  * Returns true if the user is OK to log in, otherwise returns 0
-@@ -193,7 +220,7 @@ static int
- ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name)
- {
- 	krb5_principal princ;
--	int retval;
-+	int retval, matched;
- 	const char *errmsg;
- 	int k5login_exists;
- 
-@@ -216,17 +243,42 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name)
- 	if (k5login_exists &&
- 	    ssh_krb5_kuserok(krb_context, princ, name, k5login_exists)) {
- 		retval = 1;
--		logit("Authorized to %s, krb5 principal %s (krb5_kuserok)",
--		    name, (char *)client->displayname.value);
-+	    errmsg = "krb5_kuserok";
- 	} else if (ssh_gssapi_krb5_cmdok(princ, client->exportedname.value,
- 		name, k5login_exists)) {
- 		retval = 1;
--		logit("Authorized to %s, krb5 principal %s "
--		    "(ssh_gssapi_krb5_cmdok)",
--		    name, (char *)client->displayname.value);
-+		errmsg = "ssh_gssapi_krb5_cmdok";
- 	} else
- 		retval = 0;
- 
-+	if ((retval == 1) && (options.gss_indicators != NULL)) {
-+		/* At this point the configuration enforces presence of indicators
-+		 * so we drop the authorization result again */
-+		retval = 0;
-+		if (client->indicators) {
-+			matched = -1;
-+			retval = ssh_gssapi_check_indicators(client, &matched);
-+			if (retval != 0) {
-+				retval = (retval == 1);
-+				logit("Ticket contains indicator %s, "
-+					"krb5 principal %s is %s",
-+					client->indicators[matched],
-+					(char *)client->displayname.value,
-+				        retval ? "allowed" : "denied");
-+				goto cont;
-+			}
-+		}
-+		if (retval == 0) {
-+			logit("GSSAPI authentication indicators enforced "
-+				"but not matched. krb5 principal %s denied",
-+			(char *)client->displayname.value);
-+		}
-+	}
-+cont:
-+	if (retval == 1) {
-+		logit("Authorized to %s, krb5 principal %s (%s)",
-+		    name, (char *)client->displayname.value, errmsg);
-+	}
- 	krb5_free_principal(krb_context, princ);
- 	return retval;
- }
-diff --git a/gss-serv.c b/gss-serv.c
-index 9d5435eda..5c0491cf1 100644
---- a/gss-serv.c
-+++ b/gss-serv.c
-@@ -54,7 +54,7 @@ extern ServerOptions options;
+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
+@@ -53,7 +53,7 @@ extern ServerOptions options;
  
  static ssh_gssapi_client gssapi_client =
      { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER, GSS_C_NO_CREDENTIAL,
@@ -155,7 +21,7 @@ index 9d5435eda..5c0491cf1 100644
  
  ssh_gssapi_mech gssapi_null_mech =
      { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL, NULL};
-@@ -296,6 +296,92 @@ ssh_gssapi_parse_ename(Gssctxt *ctx, gss_buffer_t ename, gss_buffer_t name)
+@@ -295,6 +295,95 @@ ssh_gssapi_parse_ename(Gssctxt *ctx, gss
  	return GSS_S_COMPLETE;
  }
  
@@ -163,9 +29,10 @@ index 9d5435eda..5c0491cf1 100644
 +/* 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.
-+ * Each indicator is a utf8 string. */
++ * Each indicator is an utf8 string. */
 +
 +#define AUTH_INDICATORS_TAG "auth-indicators"
++#define SSH_GSSAPI_MAX_INDICATORS 64
 +
 +/* Privileged (called from accept_secure_ctx) */
 +static OM_uint32
@@ -188,24 +55,7 @@ index 9d5435eda..5c0491cf1 100644
 +		return (0);
 +	}
 +
-+	count = 0;
-+	for (i = 0; i < attrs->count; i++) {
-+		/* skip anything but auth-indicators */
-+		if (((sizeof(AUTH_INDICATORS_TAG) - 1) != attrs->elements[i].length) ||
-+		    strncmp(AUTH_INDICATORS_TAG,
-+			    attrs->elements[i].value,
-+			    sizeof(AUTH_INDICATORS_TAG) - 1) != 0)
-+			continue;
-+		count++;
-+	}
-+
-+	if (count == 0) {
-+		/* No auth-indicators in the ticket */
-+		(void) gss_release_buffer_set(&ctx->minor, &attrs);
-+		return (0);
-+	}
-+
-+	client->indicators = recallocarray(NULL, 0, count + 1, sizeof(char*));
++	client->indicators = NULL;
 +	count = 0;
 +	for (i = 0; i < attrs->count; i++) {
 +		authenticated = 0;
@@ -213,22 +63,33 @@ index 9d5435eda..5c0491cf1 100644
 +		more = -1;
 +		/* skip anything but auth-indicators */
 +		if (((sizeof(AUTH_INDICATORS_TAG) - 1) != attrs->elements[i].length) ||
-+		    strncmp(AUTH_INDICATORS_TAG,
-+			    attrs->elements[i].value,
-+			    sizeof(AUTH_INDICATORS_TAG) - 1) != 0)
++		    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);
-+			if (ctx->major != GSS_S_COMPLETE) {
++							    &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;
++				}
++
++				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';
@@ -237,18 +98,26 @@ index 9d5435eda..5c0491cf1 100644
 +		}
 +	}
 +
++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++)
++			free(client->indicators[i]);
++		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);
 +}
 +
-+
  /* Extract the client details from a given context. This can only reliably
   * be called once for a context */
  
-@@ -385,6 +471,12 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
+@@ -384,6 +473,12 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_g
  	}
  
  	gss_release_buffer(&ctx->minor, &ename);
@@ -261,7 +130,7 @@ index 9d5435eda..5c0491cf1 100644
  
  	/* We can't copy this structure, so we just move the pointer to it */
  	client->creds = ctx->client_creds;
-@@ -447,6 +539,7 @@ int
+@@ -446,6 +541,7 @@ int
  ssh_gssapi_userok(char *user, struct passwd *pw, int kex)
  {
  	OM_uint32 lmin;
@@ -269,34 +138,174 @@ index 9d5435eda..5c0491cf1 100644
  
  	(void) kex; /* used in privilege separation */
  
-@@ -465,6 +558,14 @@ ssh_gssapi_userok(char *user, struct passwd *pw, int kex)
+@@ -464,8 +560,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);
+-			explicit_bzero(&gssapi_client,
+-			    sizeof(ssh_gssapi_client));
 +
 +			if (gssapi_client.indicators != NULL) {
-+				for(i = 0; gssapi_client.indicators[i] != NULL; i++) {
++				for (i = 0; gssapi_client.indicators[i] != NULL; i++)
 +					free(gssapi_client.indicators[i]);
-+				}
 +				free(gssapi_client.indicators);
 +			}
 +
- 			explicit_bzero(&gssapi_client,
- 			    sizeof(ssh_gssapi_client));
++			explicit_bzero(&gssapi_client, sizeof(ssh_gssapi_client));
  			return 0;
-diff --git a/servconf.c b/servconf.c
-index e7e4ad046..aab653244 100644
---- a/servconf.c
-+++ b/servconf.c
-@@ -147,6 +147,7 @@ initialize_server_options(ServerOptions *options)
+ 		}
+ 	else
+diff --color -ruNp a/gss-serv-krb5.c b/gss-serv-krb5.c
+--- a/gss-serv-krb5.c	2026-03-10 12:43:36.823015336 +0100
++++ b/gss-serv-krb5.c	2026-03-11 12:58:56.024455238 +0100
+@@ -43,6 +43,7 @@
+ #include "log.h"
+ #include "misc.h"
+ #include "servconf.h"
++#include "match.h"
+ 
+ #include "ssh-gss.h"
+ 
+@@ -87,6 +88,33 @@ ssh_gssapi_krb5_init(void)
+ 	return 1;
+ }
+ 
++/* Check if any of the indicators in the Kerberos ticket match
++ * 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
++ */
++
++static int
++ssh_gssapi_check_indicators(ssh_gssapi_client *client, int *matched)
++{
++	int ret;
++	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) {
++			*matched = i;
++			return ret;
++		}
++	}
++	/* No rule matched */
++	return 0;
++}
++
+ /* Check if this user is OK to login. This only works with krb5 - other
+  * GSSAPI mechanisms will need their own.
+  * Returns true if the user is OK to log in, otherwise returns 0
+@@ -193,15 +221,15 @@ static int
+ ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name)
+ {
+ 	krb5_principal princ;
+-	int retval;
++	int retval, matched, success;
+ 	const char *errmsg;
+ 	int k5login_exists;
+ 
+ 	if (ssh_gssapi_krb5_init() == 0)
+ 		return 0;
+ 
+-	if ((retval = krb5_parse_name(krb_context, client->exportedname.value,
+-	    &princ))) {
++	retval = krb5_parse_name(krb_context, client->exportedname.value, &princ);
++	if (retval) {
+ 		errmsg = krb5_get_error_message(krb_context, retval);
+ 		logit("krb5_parse_name(): %.100s", errmsg);
+ 		krb5_free_error_message(krb_context, errmsg);
+@@ -216,17 +244,60 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client
+ 	if (k5login_exists &&
+ 	    ssh_krb5_kuserok(krb_context, princ, name, k5login_exists)) {
+ 		retval = 1;
+-		logit("Authorized to %s, krb5 principal %s (krb5_kuserok)",
+-		    name, (char *)client->displayname.value);
++		errmsg = "krb5_kuserok";
+ 	} else if (ssh_gssapi_krb5_cmdok(princ, client->exportedname.value,
+ 		name, k5login_exists)) {
+ 		retval = 1;
+-		logit("Authorized to %s, krb5 principal %s "
+-		    "(ssh_gssapi_krb5_cmdok)",
+-		    name, (char *)client->displayname.value);
+-	} else
++		errmsg = "ssh_gssapi_krb5_cmdok";
++	} else {
++		retval = 0;
++		goto out;
++	}
++
++	/* At this point we are good if no indicators were defined */
++	if (options.gss_indicators == NULL) {
++		retval = 1;
++		goto out;
++	}
++
++	/* At this point we have indicators defined in the configuration,
++	 * if clientt did not provide any indicators, we reject */
++	if (!client->indicators) {
++		retval = 0;
++		logit("GSSAPI authentication indicators enforced "
++		      "but indicators not provided by the client. "
++		      "krb5 principal %s denied",
++		      (char *)client->displayname.value);
++		goto out;
++	}
++
++	/* At this point the configuration enforces presence of indicators
++	 * check the match */
++	matched = -1;
++	success = ssh_gssapi_check_indicators(client, &matched);
++
++	switch (success) {
++	case 1:
++		logit("Provided indicator %s allowed by the configuration",
++		      client->indicators[matched]);
++		retval = 1;
++		break;
++	case -1:
++		logit("Provided indicator %s rejected by the configuration",
++		      client->indicators[matched]);
++		retval = 0;
++		break;
++	default:
++		logit("Provided indicators do not match the configuration");
+ 		retval = 0;
++		break;
++	}
+ 
++out:
++	if (retval == 1) {
++		logit("Authorized to %s, krb5 principal %s (%s)",
++		      name, (char *)client->displayname.value, errmsg);
++	}
+ 	krb5_free_principal(krb_context, princ);
+ 	return retval;
+ }
+diff --color -ruNp a/servconf.c b/servconf.c
+--- a/servconf.c	2026-03-10 12:43:36.928060353 +0100
++++ b/servconf.c	2026-03-11 13:20:09.725354925 +0100
+@@ -144,6 +144,7 @@ initialize_server_options(ServerOptions
+ 	options->gss_keyex = -1;
+ 	options->gss_cleanup_creds = -1;
  	options->gss_strict_acceptor = -1;
++	options->gss_indicators = NULL;
  	options->gss_store_rekey = -1;
  	options->gss_kex_algorithms = NULL;
-+	options->gss_indicators = NULL;
  	options->use_kuserok = -1;
- 	options->enable_k5users = -1;
- 	options->password_authentication = -1;
-@@ -598,7 +599,7 @@ typedef enum {
+@@ -557,6 +558,7 @@ fill_default_server_options(ServerOption
+ 	CLEAR_ON_NONE(options->routing_domain);
+ 	CLEAR_ON_NONE(options->host_key_agent);
+ 	CLEAR_ON_NONE(options->per_source_penalty_exempt);
++	CLEAR_ON_NONE(options->gss_indicators);
+ 
+ 	for (i = 0; i < options->num_host_key_files; i++)
+ 		CLEAR_ON_NONE(options->host_key_files[i]);
+@@ -594,7 +596,7 @@ typedef enum {
  	sPerSourcePenalties, sPerSourcePenaltyExemptList,
  	sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile,
  	sGssAuthentication, sGssCleanupCreds, sGssEnablek5users, sGssStrictAcceptor,
@@ -305,7 +314,7 @@ index e7e4ad046..aab653244 100644
  	sAcceptEnv, sSetEnv, sPermitTunnel,
  	sMatch, sPermitOpen, sPermitListen, sForceCommand, sChrootDirectory,
  	sUsePrivilegeSeparation, sAllowAgentForwarding,
-@@ -694,6 +695,7 @@ static struct {
+@@ -690,6 +692,7 @@ static struct {
  	{ "gssapistorecredentialsonrekey", sGssStoreRekey, SSHCFG_GLOBAL },
  	{ "gssapikexalgorithms", sGssKexAlgorithms, SSHCFG_GLOBAL },
  	{ "gssapienablek5users", sGssEnablek5users, SSHCFG_ALL },
@@ -313,7 +322,7 @@ index e7e4ad046..aab653244 100644
  #else
  	{ "gssapiauthentication", sUnsupported, SSHCFG_ALL },
  	{ "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL },
-@@ -703,6 +705,7 @@ static struct {
+@@ -699,6 +702,7 @@ static struct {
  	{ "gssapistorecredentialsonrekey", sUnsupported, SSHCFG_GLOBAL },
  	{ "gssapikexalgorithms", sUnsupported, SSHCFG_GLOBAL },
  	{ "gssapienablek5users", sUnsupported, SSHCFG_ALL },
@@ -321,7 +330,7 @@ index e7e4ad046..aab653244 100644
  #endif
  	{ "gssusesessionccache", sUnsupported, SSHCFG_GLOBAL },
  	{ "gssapiusesessioncredcache", sUnsupported, SSHCFG_GLOBAL },
-@@ -1730,6 +1733,15 @@ process_server_config_line_depth(ServerOptions *options, char *line,
+@@ -1715,6 +1719,15 @@ process_server_config_line_depth(ServerO
  			options->gss_kex_algorithms = xstrdup(arg);
  		break;
  
@@ -337,7 +346,7 @@ index e7e4ad046..aab653244 100644
  	case sPasswordAuthentication:
  		intptr = &options->password_authentication;
  		goto parse_flag;
-@@ -3351,6 +3363,7 @@ dump_config(ServerOptions *o)
+@@ -3329,6 +3342,7 @@ dump_config(ServerOptions *o)
  	dump_cfg_fmtint(sGssStrictAcceptor, o->gss_strict_acceptor);
  	dump_cfg_fmtint(sGssStoreRekey, o->gss_store_rekey);
  	dump_cfg_string(sGssKexAlgorithms, o->gss_kex_algorithms);
@@ -345,10 +354,9 @@ index e7e4ad046..aab653244 100644
  #endif
  	dump_cfg_fmtint(sPasswordAuthentication, o->password_authentication);
  	dump_cfg_fmtint(sKbdInteractiveAuthentication,
-diff --git a/servconf.h b/servconf.h
-index 7c7e5d434..7c41df417 100644
---- a/servconf.h
-+++ b/servconf.h
+diff --color -ruNp a/servconf.h b/servconf.h
+--- a/servconf.h	2026-03-10 12:43:36.833119920 +0100
++++ b/servconf.h	2026-03-11 13:21:36.742117033 +0100
 @@ -181,6 +181,7 @@ typedef struct {
  	char   **allow_groups;
  	u_int num_deny_groups;
@@ -357,7 +365,7 @@ index 7c7e5d434..7c41df417 100644
  
  	u_int num_subsystems;
  	char   **subsystem_name;
-@@ -310,6 +311,7 @@ TAILQ_HEAD(include_list, include_item);
+@@ -309,6 +310,7 @@ TAILQ_HEAD(include_list, include_item);
  		M_CP_STROPT(routing_domain); \
  		M_CP_STROPT(permit_user_env_allowlist); \
  		M_CP_STROPT(pam_service_name); \
@@ -365,36 +373,10 @@ index 7c7e5d434..7c41df417 100644
  		M_CP_STRARRAYOPT(authorized_keys_files, num_authkeys_files); \
  		M_CP_STRARRAYOPT(allow_users, num_allow_users); \
  		M_CP_STRARRAYOPT(deny_users, num_deny_users); \
-diff --git a/ssh-gss.h b/ssh-gss.h
-index a894e23c9..59cf46d47 100644
---- a/ssh-gss.h
-+++ b/ssh-gss.h
-@@ -34,6 +34,12 @@
- #include <gssapi/gssapi.h>
- #endif
- 
-+#ifdef HAVE_GSSAPI_EXT_H
-+#include <gssapi_ext.h>
-+#elif defined(HAVE_GSSAPI_GSSAPI_EXT_H)
-+#include <gssapi/gssapi_ext.h>
-+#endif
-+
- #ifdef KRB5
- # ifndef HEIMDAL
- #  ifdef HAVE_GSSAPI_GENERIC_H
-@@ -107,6 +113,7 @@ typedef struct {
- 	ssh_gssapi_ccache store;
- 	int used;
- 	int updated;
-+	char **indicators; /* auth indicators */
- } ssh_gssapi_client;
- 
- typedef struct ssh_gssapi_mech_struct {
-diff --git a/sshd_config.5 b/sshd_config.5
-index 583a01cdb..90ab87edd 100644
---- a/sshd_config.5
-+++ b/sshd_config.5
-@@ -785,6 +785,50 @@ gss-nistp256-sha256-
+diff --color -ruNp a/sshd_config.5 b/sshd_config.5
+--- a/sshd_config.5	2026-03-10 12:43:36.859313302 +0100
++++ b/sshd_config.5	2026-03-11 13:28:04.541970063 +0100
+@@ -785,6 +785,52 @@ gss-nistp256-sha256-
  gss-curve25519-sha256-
  .Ed
  This option only applies to connections using GSSAPI.
@@ -441,10 +423,33 @@ index 583a01cdb..90ab87edd 100644
 +FIDO2-based pre-authentication in FreeIPA, using FIDO2 USB and NFC tokens
 +.El
 +.Pp
-+The default is to not use GSSAPI authentication indicators for access decisions.
++The default
++.Dq none
++is to not use GSSAPI authentication indicators for access decisions.
  .It Cm HostbasedAcceptedAlgorithms
  The default is handled system-wide by
  .Xr crypto-policies 7 .
--- 
-2.49.0
-
+diff --color -ruNp a/ssh-gss.h b/ssh-gss.h
+--- a/ssh-gss.h	2026-03-10 12:43:36.898148309 +0100
++++ b/ssh-gss.h	2026-03-11 13:23:07.601956965 +0100
+@@ -34,6 +34,12 @@
+ #include <gssapi/gssapi.h>
+ #endif
+ 
++#ifdef HAVE_GSSAPI_EXT_H
++#include <gssapi_ext.h>
++#elif defined(HAVE_GSSAPI_GSSAPI_EXT_H)
++#include <gssapi/gssapi_ext.h>
++#endif
++
+ #ifdef KRB5
+ # ifndef HEIMDAL
+ #  ifdef HAVE_GSSAPI_GENERIC_H
+@@ -112,6 +118,7 @@ typedef struct {
+ 	ssh_gssapi_ccache store;
+ 	int used;
+ 	int updated;
++	char **indicators; /* auth indicators */
+ } ssh_gssapi_client;
+ 
+ typedef struct ssh_gssapi_mech_struct {

                 reply	other threads:[~2026-05-30  1:18 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=178010391315.1.15221795594920214601.rpms-gsi-openssh-52f242b91bc2@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