From: Scott Mayhew <smayhew@redhat.com>
To: steved@redhat.com
Cc: =carnil@debian.org, linux-nfs@vger.kernel.org
Subject: [nfs-utils PATCH RFC 4/4] gssd: add a helper to determine the set of encryption types to pass to limit_krb5_enctypes()
Date: Fri, 13 Feb 2026 17:40:12 -0500 [thread overview]
Message-ID: <20260213224012.2608126-5-smayhew@redhat.com> (raw)
In-Reply-To: <20260213224012.2608126-1-smayhew@redhat.com>
When the MIT kerberos library does a TGS request it initially does so
with referrals enabled, using its default enctype list instead of the
application-provided one. It still ensures that the resulting ticket is
using an enctype from the application-provided list, it just might not
be the highest priority enctype from the application-provided list.
That can result in the machine cred's service ticket using a different
enctype than a user cred's service ticket (particularly in the case of
contrained delegation with gssproxy), which will lead to XDR decoding
failures in the kernel. See https://bugs.debian.org/1120598.
The best way to combat this to configure the krb5 library's
permitted_enctypes list to have the same order as the kernel's
gss_krb5_prepare_enctype_priority_list (which is set at build time), but
not all distros do that. The second best way is to make sure our list
is ordered according to the krb5 library's list, which can be
accomplished via the helper function added by this patch.
The list will be the intersection of:
1. allowed_enctypes - If allowed-enctypes is defined in nfs.conf, this
is processed via get_allowed_enctypes() during gssd startup.
2. krb5_enctypes - This is the list of enctypes passed in the upcall
from the kernel, and is processed via handle_gssd_upcall() ->
parse_enctypes().
3. lib_enctypes - Processed via get_krb5_library_permitted_enctypes()
during gssd startup.
Signed-off-by: Scott Mayhew <smayhew@redhat.com>
---
utils/gssd/krb5_util.c | 172 ++++++++++++++++++++++++++++++++++-------
1 file changed, 143 insertions(+), 29 deletions(-)
diff --git a/utils/gssd/krb5_util.c b/utils/gssd/krb5_util.c
index bc07f852..bc063a8b 100644
--- a/utils/gssd/krb5_util.c
+++ b/utils/gssd/krb5_util.c
@@ -164,6 +164,14 @@ char *allowed_enctypes_string = NULL;
int num_lib_enctypes = 0;
krb5_enctype *lib_enctypes = NULL;
char *lib_enctypes_string = NULL;
+
+/*
+ * The final set of encryption types that will be used in
+ * limit_krb5_enctypes(). See determine_enctypes() below.
+ */
+int num_set_enctypes = 0;
+krb5_enctype *set_enctypes = NULL;
+char *set_enctypes_string = NULL;
#endif
/*==========================*/
@@ -1731,6 +1739,128 @@ out:
return ret;
}
+/*
+ * Helper to determine the final set of enctypes that will be passed to
+ * gss_set_allowable_enctypes() in limit_krb5_enctypes().
+ *
+ * It will be the intersection of:
+ *
+ * 1. allowed_enctypes - If allowed-enctypes is defined in nfs.conf, this is
+ * processed via get_allowed_enctypes() during gssd startup.
+ * 2. krb5_enctypes - This is the list of enctypes passed in the upcall from
+ * the kernel, and is processed via handle_gssd_upcall() -> parse_enctypes().
+ * 3. lib_enctypes - Processed via get_krb5_library_permitted_enctypes() during
+ * gssd startup.
+ *
+ * It will be ordered according to lib_enctypes. This is necessary because when
+ * the MIT kerberos library does a TGS request it initially does so with
+ * referrals enabled, using its default enctype list instead of the application-
+ * provided one. It still ensures that the resulting ticket is using an enctype
+ * from the application-provided list, it just might not be the highest priority
+ * enctype from the application-provided list.
+ *
+ * That can result in the machine cred's service ticket using a different
+ * enctype than a user cred's service ticket (particularly in the case of
+ * contrained delegation with gssproxy), which will lead to XDR decoding
+ * failures in the kernel.
+ *
+ * The best way to combat this to configure the krb5 library's
+ * permitted_enctypes list to have the same order as the kernel's
+ * gss_krb5_prepare_enctype_priority_list (which is set at build time), but not
+ * all distros do that. The second best way is to make sure our list is ordered
+ * according to the krb5 library's list, hence this helper function.
+ */
+static int
+determine_enctypes(krb5_enctype **set_enctypes, int *num_set_enctypes,
+ char **set_enctypes_string)
+{
+ extern int num_allowed_enctypes, num_krb5_enctypes, num_lib_enctypes;
+ extern krb5_enctype *allowed_enctypes, *krb5_enctypes, *lib_enctypes;
+ extern char *allowed_enctypes_string, *krb5_enctypes_string,
+ *lib_enctypes_string;
+ krb5_enctype *enctypes;
+ int num_enctypes = 0;
+ char *enctypes_string;
+ int i, j, k;
+
+ if (krb5_enctypes) {
+ printerr(2, "%s: kernel enctypes: %s\n",
+ __func__, krb5_enctypes_string);
+ } else {
+ printerr(2, "%s: kernel enctype list is empty\n",
+ __func__);
+ return -1;
+ }
+
+ if (lib_enctypes) {
+ printerr(2, "%s: krb5 library enctypes: %s\n",
+ __func__, lib_enctypes_string);
+ } else {
+ printerr(2, "%s: krb5 library enctype list is empty\n",
+ __func__);
+ return -1;
+ }
+
+ if (allowed_enctypes) {
+ printerr(2, "%s: config allowed enctypes: %s\n",
+ __func__, allowed_enctypes_string);
+ }
+
+ if (allowed_enctypes) {
+ enctypes = (krb5_enctype *) calloc(num_allowed_enctypes,
+ sizeof(krb5_enctype));
+ if (enctypes == NULL)
+ return ENOMEM;
+ for (i = 0; i < num_lib_enctypes; i++) {
+ for (j = 0; j < num_krb5_enctypes; j++) {
+ if (lib_enctypes[i] == krb5_enctypes[j]) {
+ for (k = 0; k < num_allowed_enctypes; k++) {
+ if (lib_enctypes[i] == allowed_enctypes[k]) {
+ enctypes[num_enctypes++] = lib_enctypes[i];
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+ } else {
+ enctypes = (krb5_enctype *) calloc(num_krb5_enctypes,
+ sizeof(krb5_enctype));
+ if (enctypes == NULL)
+ return ENOMEM;
+ for (i = 0; i < num_lib_enctypes; i++) {
+ for (j = 0; j < num_krb5_enctypes; j++) {
+ if (lib_enctypes[i] == krb5_enctypes[j]) {
+ enctypes[num_enctypes++] = lib_enctypes[i];
+ break;
+ }
+ }
+ }
+ }
+
+ if (num_enctypes > 0) {
+ if (enctypes_list_to_string(enctypes, num_enctypes,
+ &enctypes_string) != 0) {
+ printerr(2, "%s: warning: enctypes_list_to_string() failed\n",
+ __func__);
+ return -1;
+ }
+ printerr(2, "%s: result enctypes: %s\n",
+ __func__, enctypes_string);
+ } else {
+ printerr(2, "%s: no result enctypes\n",
+ __func__);
+ free(enctypes);
+ return -1;
+ }
+
+ *set_enctypes = enctypes;
+ *num_set_enctypes = num_enctypes;
+ *set_enctypes_string = enctypes_string;
+ return 0;
+}
+
/*
* this routine obtains a credentials handle via gss_acquire_cred()
* then calls gss_krb5_set_allowable_enctypes() to limit the encryption
@@ -1743,19 +1873,13 @@ out:
* 0 => all went well
* -1 => there was an error
*/
-
int
limit_krb5_enctypes(struct rpc_gss_sec *sec)
{
u_int maj_stat, min_stat;
- extern int num_krb5_enctypes;
- extern krb5_enctype *krb5_enctypes;
- extern char *krb5_enctypes_string;
- extern int num_allowed_enctypes;
- extern krb5_enctype *allowed_enctypes;
- extern char *allowed_enctypes_string;
- int num_set_enctypes;
- krb5_enctype *set_enctypes;
+ extern int num_set_enctypes;
+ extern krb5_enctype *set_enctypes;
+ extern char *set_enctypes_string;
int err = -1;
if (sec->cred == GSS_C_NO_CREDENTIAL) {
@@ -1764,28 +1888,18 @@ limit_krb5_enctypes(struct rpc_gss_sec *sec)
return -1;
}
- if (allowed_enctypes) {
- printerr(2, "%s: using allowed enctypes from config: %s\n",
- __func__, allowed_enctypes_string);
- num_set_enctypes = num_allowed_enctypes;
- set_enctypes = allowed_enctypes;
- } else if (krb5_enctypes) {
- printerr(2, "%s: using enctypes from the kernel: %s\n",
- __func__, krb5_enctypes_string);
- num_set_enctypes = num_krb5_enctypes;
- set_enctypes = krb5_enctypes;
- } else {
- /*
- * If we didn't get a list of enctypes from the kernel, that
- * would mean it did a v0 upcall which is for older gssd's.
- * That would indicate a serious problem, so we shouldn't
- * continue.
- */
- printerr(0, "%s: no enctypes received from the kernel, and "
- "allowed-enctypes not set in the config\n", __func__);
- return -1;
+ if (set_enctypes == NULL) {
+ err = determine_enctypes(&set_enctypes, &num_set_enctypes,
+ &set_enctypes_string);
+ if (err) {
+ printerr(2, "%s: failed to determine set_enctypes\n",
+ __func__);
+ return -1;
+ }
}
+ printerr(2, "%s: %s\n", __func__, set_enctypes_string);
+
maj_stat = gss_set_allowable_enctypes(&min_stat, sec->cred,
&krb5oid, num_set_enctypes, set_enctypes);
--
2.52.0
next prev parent reply other threads:[~2026-02-13 22:40 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-02-13 22:40 [nfs-utils PATCH RFC 0/4] Rework the handling of encryption types in rpc.gssd Scott Mayhew
2026-02-13 22:40 ` [nfs-utils PATCH RFC 1/4] gssd: remove the limit-to-legacy-enctypes option Scott Mayhew
2026-02-13 22:40 ` [nfs-utils PATCH RFC 2/4] gssd: add enctypes_list_to_string() Scott Mayhew
2026-02-13 22:40 ` [nfs-utils PATCH RFC 3/4] gssd: get the permitted enctypes from the krb5 library on startup Scott Mayhew
2026-02-13 22:40 ` Scott Mayhew [this message]
2026-02-28 17:14 ` [nfs-utils PATCH RFC 0/4] Rework the handling of encryption types in rpc.gssd Steve Dickson
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260213224012.2608126-5-smayhew@redhat.com \
--to=smayhew@redhat.com \
--cc==carnil@debian.org \
--cc=linux-nfs@vger.kernel.org \
--cc=steved@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox