Unpatch Red Hat help message

This commit is contained in:
Koichiro Iwao 2026-07-29 13:42:23 +00:00 committed by root
commit 0e56827302
7 changed files with 518 additions and 277 deletions

View File

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

View File

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

View File

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

View File

@ -0,0 +1,14 @@
diff --color -ruNp a/scp.c b/scp.c
--- a/scp.c 2026-07-14 11:40:47.754600847 +0200
+++ b/scp.c 2026-07-14 11:43:04.077524517 +0200
@@ -2070,6 +2070,10 @@ throughlocal_sftp(struct sftp_conn *from
goto out;
}
+ /* Special handling for source of '..' */
+ if (strcmp(filename, "..") == 0)
+ filename = "."; /* Download to dest, not dest/.. */
+
if (targetisdir)
abs_dst = sftp_path_append(target, filename);
else

View File

@ -24,8 +24,8 @@ index aab653244..02a9888c9 100644
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)
options->gss_keyex = 0;
if (options->gss_cleanup_creds == -1)

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,10 +9,159 @@ 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
diff --color -ruNp a/gss-serv.c b/gss-serv.c
--- a/gss-serv.c 2026-06-16 15:38:26.590728235 +0200
+++ b/gss-serv.c 2026-06-16 15:41:13.717696103 +0200
@@ -53,7 +53,7 @@ extern ServerOptions options;
static ssh_gssapi_client gssapi_client =
{ GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER, GSS_C_NO_CREDENTIAL,
- GSS_C_NO_NAME, NULL, {NULL, NULL, NULL, NULL, NULL}, 0, 0};
+ GSS_C_NO_NAME, NULL, {NULL, NULL, NULL, NULL, NULL}, 0, 0, NULL};
ssh_gssapi_mech gssapi_null_mech =
{ NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL, NULL};
@@ -295,6 +295,99 @@ ssh_gssapi_parse_ename(Gssctxt *ctx, gss
return GSS_S_COMPLETE;
}
+
+/* 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 an utf8 string. */
+
+#define AUTH_INDICATORS_TAG "auth-indicators"
+#define SSH_GSSAPI_MAX_INDICATORS 64
+
+/* Privileged (called from accept_secure_ctx) */
+static OM_uint32
+ssh_gssapi_getindicators(Gssctxt *ctx, gss_name_t gss_name, ssh_gssapi_client *client)
+{
+ gss_buffer_set_t attrs = GSS_C_NO_BUFFER_SET;
+ gss_buffer_desc value = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc display_value = GSS_C_EMPTY_BUFFER;
+ int is_mechname, authenticated, complete, more;
+ size_t count, i;
+
+ /* always initialize client->indicators */
+ client->indicators = NULL;
+
+ ctx->major = gss_inquire_name(&ctx->minor, gss_name,
+ &is_mechname, NULL, &attrs);
+ if (ctx->major != GSS_S_COMPLETE)
+ return ctx->major;
+
+ if (attrs == GSS_C_NO_BUFFER_SET) {
+ /* no indicators in the ticket */
+ return GSS_S_COMPLETE;
+ }
+
+ /* client->indicators is NULL terminated */
+ count = 0;
+ client->indicators = xcalloc(count + 1, sizeof(char *));
+
+ for (i = 0; i < attrs->count; i++) {
+ authenticated = 0;
+ complete = 0;
+ more = -1;
+
+ /* skip anything but auth-indicators */
+ if (((sizeof(AUTH_INDICATORS_TAG) - 1) != attrs->elements[i].length) ||
+ memcmp(AUTH_INDICATORS_TAG, attrs->elements[i].value,
+ 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)
+ goto out;
+
+ if (value.value == NULL || !authenticated)
+ continue;
+
+ if (count >= SSH_GSSAPI_MAX_INDICATORS) {
+ logit("ssh_gssapi_getindicators:"
+ " too many indicators, truncating at %d",
+ SSH_GSSAPI_MAX_INDICATORS);
+ goto out;
+ }
+
+ client->indicators[count] = xmalloc(value.length + 1);
+ memcpy(client->indicators[count], value.value, value.length);
+ client->indicators[count][value.length] = '\0';
+ count++;
+
+ /* add NULL terminator */
+ client->indicators = xrecallocarray(client->indicators, count,
+ count + 1, sizeof(char *));
+ }
+ }
+
+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;
+ }
+ gss_release_buffer(&ctx->minor, &value);
+ gss_release_buffer(&ctx->minor, &display_value);
+ gss_release_buffer_set(&ctx->minor, &attrs);
+ return ctx->major;
+}
+
/* Extract the client details from a given context. This can only reliably
* be called once for a context */
@@ -384,6 +477,12 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_g
}
gss_release_buffer(&ctx->minor, &ename);
+ /* Retrieve authentication indicators, if they exist */
+ if ((ctx->major = ssh_gssapi_getindicators(ctx,
+ ctx->client, client))) {
+ ssh_gssapi_error(ctx);
+ return (ctx->major);
+ }
/* We can't copy this structure, so we just move the pointer to it */
client->creds = ctx->client_creds;
@@ -446,6 +545,7 @@ int
ssh_gssapi_userok(char *user, struct passwd *pw, int kex)
{
OM_uint32 lmin;
+ size_t i;
(void) kex; /* used in privilege separation */
@@ -464,8 +564,14 @@ ssh_gssapi_userok(char *user, struct pas
gss_release_buffer(&lmin, &gssapi_client.displayname);
gss_release_buffer(&lmin, &gssapi_client.exportedname);
gss_release_cred(&lmin, &gssapi_client.creds);
- explicit_bzero(&gssapi_client,
- sizeof(ssh_gssapi_client));
+
+ if (gssapi_client.indicators != NULL) {
+ 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));
return 0;
}
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"
@ -52,7 +170,7 @@ index 03188d9b3..2c786ef14 100644
#include "ssh-gss.h"
@@ -87,6 +88,32 @@ ssh_gssapi_krb5_init(void)
@@ -87,6 +88,33 @@ ssh_gssapi_krb5_init(void)
return 1;
}
@ -67,6 +185,7 @@ index 03188d9b3..2c786ef14 100644
+{
+ int ret;
+ u_int i;
+ *matched = -1;
+
+ /* Check indicators */
+ for (i = 0; client->indicators[i] != NULL; i++) {
@ -85,218 +204,112 @@ index 03188d9b3..2c786ef14 100644
/* 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
@@ -193,15 +221,15 @@ static int
ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name)
{
krb5_principal princ;
- int retval;
+ int retval, matched;
+ int retval, matched, success;
const char *errmsg;
int k5login_exists;
@@ -216,17 +243,42 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name)
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";
+ 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;
+ if ((retval == 1) && (options.gss_indicators != NULL)) {
+ /* At this point the configuration enforces presence of indicators
+ * so we drop the authorization result again */
+ } else {
+ 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);
+ }
+ goto out;
+ }
+cont:
+
+ /* 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);
+ 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;
static ssh_gssapi_client gssapi_client =
{ GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER, GSS_C_NO_CREDENTIAL,
- GSS_C_NO_NAME, NULL, {NULL, NULL, NULL, NULL, NULL}, 0, 0};
+ GSS_C_NO_NAME, NULL, {NULL, NULL, NULL, NULL, NULL}, 0, 0, NULL};
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)
return GSS_S_COMPLETE;
}
+
+/* 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. */
+
+#define AUTH_INDICATORS_TAG "auth-indicators"
+
+/* Privileged (called from accept_secure_ctx) */
+static OM_uint32
+ssh_gssapi_getindicators(Gssctxt *ctx, gss_name_t gss_name, ssh_gssapi_client *client)
+{
+ gss_buffer_set_t attrs = GSS_C_NO_BUFFER_SET;
+ gss_buffer_desc value = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc display_value = GSS_C_EMPTY_BUFFER;
+ int is_mechname, authenticated, complete, more;
+ size_t count, i;
+
+ ctx->major = gss_inquire_name(&ctx->minor, gss_name,
+ &is_mechname, NULL, &attrs);
+ if (ctx->major != GSS_S_COMPLETE) {
+ return (ctx->major);
+ }
+
+ if (attrs == GSS_C_NO_BUFFER_SET) {
+ /* No indicators in the ticket */
+ 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*));
+ count = 0;
+ for (i = 0; i < attrs->count; i++) {
+ authenticated = 0;
+ complete = 0;
+ more = -1;
+ /* skip anything but auth-indicators */
+ if (((sizeof(AUTH_INDICATORS_TAG) - 1) != attrs->elements[i].length) ||
+ strncmp(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) {
+ goto out;
+ }
+
+ if ((value.value != NULL) && authenticated) {
+ client->indicators[count] = xmalloc(value.length + 1);
+ memcpy(client->indicators[count], value.value, value.length);
+ client->indicators[count][value.length] = '\0';
+ count++;
+ }
+ }
+ }
+
+out:
+ (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)
}
gss_release_buffer(&ctx->minor, &ename);
+ /* Retrieve authentication indicators, if they exist */
+ if ((ctx->major = ssh_gssapi_getindicators(ctx,
+ ctx->client, client))) {
+ ssh_gssapi_error(ctx);
+ return (ctx->major);
+ }
/* We can't copy this structure, so we just move the pointer to it */
client->creds = ctx->client_creds;
@@ -447,6 +539,7 @@ int
ssh_gssapi_userok(char *user, struct passwd *pw, int kex)
{
OM_uint32 lmin;
+ size_t i;
(void) kex; /* used in privilege separation */
@@ -465,6 +558,14 @@ ssh_gssapi_userok(char *user, struct passwd *pw, int kex)
gss_release_buffer(&lmin, &gssapi_client.displayname);
gss_release_buffer(&lmin, &gssapi_client.exportedname);
gss_release_cred(&lmin, &gssapi_client.creds);
+
+ if (gssapi_client.indicators != NULL) {
+ 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));
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)
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 +318,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 +326,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 +334,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 +350,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 +358,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 +369,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 +377,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 +427,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: 23%{?dist}.alma.1
Release: 25%{?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
@ -240,6 +240,10 @@ Patch1039: openssh-9.9p1-authorized-keys-principles-option.patch
# upstream 607bd871ec029e9aa22e632a22547250f3cae223
# upstream 1340d3fa8e4bb122906a82159c4c9b91584d65ce
Patch1040: openssh-9.9p1-proxyjump-username-validity-checks.patch
# upstream 36480181fa22f98e180b4f9e10203480c0346c78
Patch1041: openssh-9.9p1-scp-remote-glob.patch
# upstream e8bdfb151a356d0171fea4194dd205fbb252be23
Patch1042: openssh-9.9p1-cve-2026-60002.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
@ -446,6 +450,8 @@ gpgv2 --quiet --keyring %{SOURCE3} %{SOURCE1} %{SOURCE0}
%patch -P 1038 -p1 -b .ecdsa-incomplete-application
%patch -P 1039 -p1 -b .authorized-keys-principles-option
%patch -P 1040 -p1 -b .proxyjump-username-validity-checks
%patch -P 1041 -p1 -b .scp-remote-glob
%patch -P 1042 -p1 -b .cve-2026-60002
%patch -P 100 -p1 -b .coverity
@ -726,9 +732,28 @@ test -f %{sysconfig_anaconda} && \
%attr(0755,root,root) %{_libdir}/sshtest/sk-dummy.so
%changelog
* Wed May 20 2026 Koichiro Iwao <meta@almalinux.org> - 9.9p1-23.alma.1
* Wed Jul 29 2026 Koichiro Iwao <meta@almalinux.org> - 9.9p1-25.alma.1
- Unpatch Red Hat help message
* Tue Jul 14 2026 Zoltan Fridrich <zfridric@redhat.com> - 9.9p1-25
- CVE-2026-59996: Fix remote glob result of ".." causing files to be placed
in unintended parent directories when scp performs remote-to-remote copy
via the local host
Resolves: RHEL-193170
- CVE-2026-60002: Fix use-after-free in cached hostkey during key re-exchange
Resolves: RHEL-193016
* Tue Jun 30 2026 Zoltan Fridrich <zfridric@redhat.com> - 9.9p1-24
- CVE-2026-55653: Fix double free in openssh DH-GEX client path during
FIPS known-group validation that leads to client-side denial of service
Resolves: RHEL-186435
- CVE-2026-55654: Fix heap out-of-bounds read during GSSAPI indicator
cleanup due to missing NULL terminator
Resolves: RHEL-185826
- CVE-2026-55655: Fix MITM of X11 forwarding via abstract UNIX socket
pre-binding
Resolves: RHEL-185852
* Mon Apr 13 2026 Zoltan Fridrich <zfridric@redhat.com> - 9.9p1-23
- CVE-2026-35385: Fix privilege escalation via scp legacy protocol
when not in preserving file mode