Fix GSSAPI authentication indicator issues found by AI
Resolves: RHEL-154309 Signed-off-by: Zoltan Fridrich <zfridric@redhat.com>
This commit is contained in:
parent
952d882d0a
commit
5112fd1dbb
File diff suppressed because it is too large
Load Diff
@ -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 .
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -727,6 +727,8 @@ test -f %{sysconfig_anaconda} && \
|
||||
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
|
||||
|
||||
* Wed Mar 11 2026 Dmitry Belyavskiy <dbelyavs@redhat.com> - 9.9p1-21
|
||||
- Implement obtaining Kerberos tickets on behalf of user on SSH authentication
|
||||
|
||||
Loading…
Reference in New Issue
Block a user