Unpatch Red Hat help message

This commit is contained in:
Koichiro Iwao 2026-03-18 02:41:41 +00:00 committed by root
commit b70f888f14
7 changed files with 1131 additions and 937 deletions

View File

@ -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,

View File

@ -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;
}

File diff suppressed because it is too large Load Diff

View File

@ -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;
}

View File

@ -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 .

View File

@ -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 {

View File

@ -43,7 +43,7 @@
Summary: An open source implementation of SSH protocol version 2
Name: openssh
Version: %{openssh_ver}
Release: 21%{?dist}.alma.1
Release: 22%{?dist}.alma.1
URL: http://www.openssh.com/portable.html
Source0: ftp://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-%{version}.tar.gz
Source1: ftp://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-%{version}.tar.gz.asc
@ -228,6 +228,15 @@ 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
Patch1036: openssh-9.9p1-gssapi-s4u.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
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
Requires: /sbin/nologin
@ -252,7 +261,6 @@ BuildRequires: systemd-rpm-macros
BuildRequires: gcc make
BuildRequires: p11-kit-devel
BuildRequires: libfido2-devel
Recommends: p11-kit
Obsoletes: openssh-ldap < 8.3p1-4
Obsoletes: openssh-cavs < 8.4p1-5
@ -429,6 +437,8 @@ gpgv2 --quiet --keyring %{SOURCE3} %{SOURCE1} %{SOURCE0}
%patch -P 1034 -p1 -b .sshd-nogsscreds
%patch -P 1035 -p1 -b .mlkem-nist-fips
%patch -P 1036 -p1 -b .gssapi-s4u
%patch -P 1037 -p1 -b .first-match-wins
%patch -P 1038 -p1 -b .maxstartups-mistracking
%patch -P 100 -p1 -b .coverity
@ -709,9 +719,23 @@ test -f %{sysconfig_anaconda} && \
%attr(0755,root,root) %{_libdir}/sshtest/sk-dummy.so
%changelog
* Thu Mar 12 2026 Koichiro Iwao <meta@almalinux.org> - 9.9p1-21.alma.1
* Wed Mar 18 2026 Koichiro Iwao <meta@almalinux.org> - 9.9p1-22.alma.1
- Unpatch Red Hat help message
* Thu Mar 12 2026 Zoltan Fridrich <zfridric@redhat.com> - 9.9p1-22
- Remove recommendation of p11-kit
Resolves: RHEL-139070
- Only the first value of MaxStartups, PerSourceNetBlockSize and IPQoS
in sshd_config should count when defined multiple times
Resolves: RHEL-150365
- Fix mistracking of MaxStartups process exits in some situations
Resolves: RHEL-121768
- Fix GSSAPI authentication indicator issues found by AI
Resolves: RHEL-154309
- CVE-2026-3497: Fix information disclosure or denial of service due
to uninitialized variables in gssapi-keyex
Resolves: RHEL-155813
* Wed Mar 11 2026 Dmitry Belyavskiy <dbelyavs@redhat.com> - 9.9p1-21
- Implement obtaining Kerberos tickets on behalf of user on SSH authentication
Resolves: RHEL-92932