- add fix for JIRA RHEL-90238.

This commit is contained in:
Ian Kent 2025-06-09 10:45:36 +08:00
parent c4eb298f9f
commit d31310c6a5
4 changed files with 532 additions and 1 deletions

View File

@ -0,0 +1,347 @@
autofs-5.1.6 - fix ldap sasl reconnect problem
From: Ian Kent <raven@themaw.net>
When performing an ldap sasl connection a two step initialisation
was being done in an attempt to partially reuse existing connection
setup.
But if a network connectivity problem occurs the connection can end
up only half initialized and recovery after connectivity is restored
fails.
So get rid of the two step initialization, as it's benefit was at best
questionable, so that connection attempts either succeed or completely
fail. This leaves the connection completely uninitialized if there's a
network conectivity problem, ready for a new connection attempt.
Signed-off-by: Ian Kent <raven@themaw.net>
---
CHANGELOG | 1
include/lookup_ldap.h | 1
modules/cyrus-sasl.c | 131 +++++++++++++++++++++++++-------------------------
3 files changed, 68 insertions(+), 65 deletions(-)
--- autofs-5.1.4.orig/CHANGELOG
+++ autofs-5.1.4/CHANGELOG
@@ -162,6 +162,7 @@
- refactor umount_amd_ext_mount().
- add flags argument to amd do_program_mount().
- fix deadlock in master_notify_submount().
+- fix ldap sasl reconnect problem.
xx/xx/2018 autofs-5.1.5
- fix flag file permission.
--- autofs-5.1.4.orig/include/lookup_ldap.h
+++ autofs-5.1.4/include/lookup_ldap.h
@@ -87,7 +87,6 @@ struct lookup_context {
char *secret;
char *client_princ;
char *client_cc;
- int kinit_done;
int kinit_successful;
#ifdef WITH_SASL
/* Kerberos */
--- autofs-5.1.4.orig/modules/cyrus-sasl.c
+++ autofs-5.1.4/modules/cyrus-sasl.c
@@ -396,9 +396,9 @@ do_sasl_bind(unsigned logopt, LDAP *ld,
* cache, add the TGT to that cache, and set the environment variable so
* that the sasl/krb5 libraries can find our credentials.
*
- * Returns 0 upon success. ctxt->kinit_done and ctxt->kinit_successful
- * are set for cleanup purposes. The krb5 context and ccache entries in
- * the lookup_context are also filled in.
+ * Returns 0 upon success. ctxt->kinit_successful is set for cleanup
+ * purposes. The krb5 context and ccache entries in the lookup_context
+ * are also filled in.
*
* Upon failure, -1 is returned.
*/
@@ -412,9 +412,16 @@ sasl_do_kinit(unsigned logopt, struct lo
const char *realm_name;
int status, realm_length;
- if (ctxt->kinit_done)
+ status = pthread_mutex_lock(&krb5cc_mutex);
+ if (status)
+ fatal(status);
+
+ if (ctxt->kinit_successful) {
+ status = pthread_mutex_unlock(&krb5cc_mutex);
+ if (status)
+ fatal(status);
return 0;
- ctxt->kinit_done = 1;
+ }
debug(logopt,
"initializing kerberos ticket: client principal %s",
@@ -423,15 +430,14 @@ sasl_do_kinit(unsigned logopt, struct lo
ret = krb5_init_context(&ctxt->krb5ctxt);
if (ret) {
error(logopt, "krb5_init_context failed with %d", ret);
- return -1;
+ goto out_unlock;
}
ret = krb5_cc_resolve(ctxt->krb5ctxt, krb5ccval, &ctxt->krb5_ccache);
if (ret) {
error(logopt, "krb5_cc_resolve failed with error %d",
ret);
- krb5_free_context(ctxt->krb5ctxt);
- return -1;
+ goto out_free_context;
}
if (ctxt->client_princ) {
@@ -515,19 +521,11 @@ sasl_do_kinit(unsigned logopt, struct lo
goto out_cleanup_unparse;
}
- status = pthread_mutex_lock(&krb5cc_mutex);
- if (status)
- fatal(status);
-
if (krb5cc_in_use++ == 0)
/* tell the cache what the default principal is */
ret = krb5_cc_initialize(ctxt->krb5ctxt,
ctxt->krb5_ccache, krb5_client_princ);
- status = pthread_mutex_unlock(&krb5cc_mutex);
- if (status)
- fatal(status);
-
if (ret) {
error(logopt,
"krb5_cc_initialize failed with error %d", ret);
@@ -550,6 +548,10 @@ sasl_do_kinit(unsigned logopt, struct lo
}
ctxt->kinit_successful = 1;
+ status = pthread_mutex_unlock(&krb5cc_mutex);
+ if (status)
+ fatal(status);
+
debug(logopt, "Kerberos authentication was successful!");
krb5_free_unparsed_name(ctxt->krb5ctxt, tgs_name);
@@ -569,10 +571,6 @@ out_cleanup_tgs_princ:
out_cleanup_client_princ:
krb5_free_principal(ctxt->krb5ctxt, krb5_client_princ);
out_cleanup_cc:
- status = pthread_mutex_lock(&krb5cc_mutex);
- if (status)
- fatal(status);
-
if (krb5cc_in_use)
ret = krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache);
else
@@ -580,22 +578,21 @@ out_cleanup_cc:
if (ret)
warn(logopt,
"krb5_cc_destroy failed with non-fatal error %d", ret);
-
+out_free_context:
+ krb5_free_context(ctxt->krb5ctxt);
+out_unlock:
status = pthread_mutex_unlock(&krb5cc_mutex);
if (status)
fatal(status);
-
- krb5_free_context(ctxt->krb5ctxt);
-
return -1;
}
/*
* Check a client given external credential cache.
*
- * Returns 0 upon success. ctxt->kinit_done and ctxt->kinit_successful
- * are set for cleanup purposes. The krb5 context and ccache entries in
- * the lookup_context are also filled in.
+ * Returns 0 upon success. ctxt->kinit_successful is set for cleanup
+ * purposes. The krb5 context and ccache entries in the lookup_context
+ * are also filled in.
*
* Upon failure, -1 is returned.
*/
@@ -606,10 +603,18 @@ sasl_do_kinit_ext_cc(unsigned logopt, st
krb5_principal krb5_client_princ;
krb5_error_code ret;
char *cc_princ, *client_princ;
+ int status;
+
+ status = pthread_mutex_lock(&krb5cc_mutex);
+ if (status)
+ fatal(status);
- if (ctxt->kinit_done)
+ if (ctxt->kinit_successful) {
+ status = pthread_mutex_unlock(&krb5cc_mutex);
+ if (status)
+ fatal(status);
return 0;
- ctxt->kinit_done = 1;
+ }
debug(logopt,
"using external credential cache for auth: client principal %s",
@@ -618,33 +623,26 @@ sasl_do_kinit_ext_cc(unsigned logopt, st
ret = krb5_init_context(&ctxt->krb5ctxt);
if (ret) {
error(logopt, "krb5_init_context failed with %d", ret);
- return -1;
+ goto out_unlock;
}
ret = krb5_cc_resolve(ctxt->krb5ctxt, ctxt->client_cc, &ctxt->krb5_ccache);
if (ret) {
error(logopt, "krb5_cc_resolve failed with error %d",
ret);
- krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache);
- krb5_free_context(ctxt->krb5ctxt);
- return -1;
+ goto out_cleanup_cc;
}
ret = krb5_cc_get_principal(ctxt->krb5ctxt, ctxt->krb5_ccache, &def_princ);
if (ret) {
error(logopt, "krb5_cc_get_principal failed with error %d", ret);
- krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache);
- krb5_free_context(ctxt->krb5ctxt);
- return -1;
+ goto out_cleanup_cc;
}
ret = krb5_unparse_name(ctxt->krb5ctxt, def_princ, &cc_princ);
if (ret) {
error(logopt, "krb5_unparse_name failed with error %d", ret);
- krb5_free_principal(ctxt->krb5ctxt, def_princ);
- krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache);
- krb5_free_context(ctxt->krb5ctxt);
- return -1;
+ goto out_cleanup_def_princ;
}
debug(logopt, "external credential cache default principal %s", cc_princ);
@@ -667,10 +665,8 @@ sasl_do_kinit_ext_cc(unsigned logopt, st
error(logopt,
"krb5_sname_to_principal failed for "
"%s with error %d", default_client, ret);
- krb5_free_principal(ctxt->krb5ctxt, def_princ);
- krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache);
- krb5_free_context(ctxt->krb5ctxt);
- return -1;
+ krb5_free_unparsed_name(ctxt->krb5ctxt, cc_princ);
+ goto out_cleanup_def_princ;
}
@@ -681,10 +677,8 @@ sasl_do_kinit_ext_cc(unsigned logopt, st
"krb5_unparse_name failed with error %d",
ret);
krb5_free_principal(ctxt->krb5ctxt, krb5_client_princ);
- krb5_free_principal(ctxt->krb5ctxt, def_princ);
- krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache);
- krb5_free_context(ctxt->krb5ctxt);
- return -1;
+ krb5_free_unparsed_name(ctxt->krb5ctxt, cc_princ);
+ goto out_cleanup_def_princ;
}
debug(logopt,
@@ -711,10 +705,7 @@ sasl_do_kinit_ext_cc(unsigned logopt, st
if (!ctxt->client_princ)
krb5_free_unparsed_name(ctxt->krb5ctxt, client_princ);
krb5_free_unparsed_name(ctxt->krb5ctxt, cc_princ);
- krb5_free_principal(ctxt->krb5ctxt, def_princ);
- krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache);
- krb5_free_context(ctxt->krb5ctxt);
- return -1;
+ goto out_cleanup_def_princ;
}
if (!ctxt->client_princ)
@@ -725,15 +716,24 @@ sasl_do_kinit_ext_cc(unsigned logopt, st
/* Set the environment variable to point to the external cred cache */
if (setenv(krb5ccenv, ctxt->client_cc, 1) != 0) {
error(logopt, "setenv failed with %d", errno);
- krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache);
- krb5_free_context(ctxt->krb5ctxt);
- return -1;
+ goto out_cleanup_cc;
}
ctxt->kinit_successful = 1;
debug(logopt, "Kerberos authentication was successful!");
return 0;
+
+out_cleanup_def_princ:
+ krb5_free_principal(ctxt->krb5ctxt, def_princ);
+out_cleanup_cc:
+ krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache);
+ krb5_free_context(ctxt->krb5ctxt);
+out_unlock:
+ status = pthread_mutex_unlock(&krb5cc_mutex);
+ if (status)
+ fatal(status);
+ return -1;
}
/*
@@ -975,11 +975,19 @@ void autofs_sasl_dispose(struct ldap_con
{
int status, ret;
+ status = pthread_mutex_lock(&krb5cc_mutex);
+ if (status)
+ fatal(status);
+
if (ctxt->sasl_mech && !strncmp(ctxt->sasl_mech, "EXTERNAL", 8)) {
if (conn && conn->ldap) {
ldap_unbind_s(conn->ldap);
conn->ldap = NULL;
+ ctxt->kinit_successful = 0;
}
+ status = pthread_mutex_unlock(&krb5cc_mutex);
+ if (status)
+ fatal(status);
return;
}
@@ -989,10 +997,6 @@ void autofs_sasl_dispose(struct ldap_con
}
if (ctxt->kinit_successful) {
- status = pthread_mutex_lock(&krb5cc_mutex);
- if (status)
- fatal(status);
-
if (--krb5cc_in_use || ctxt->client_cc)
ret = krb5_cc_close(ctxt->krb5ctxt, ctxt->krb5_ccache);
else
@@ -1001,19 +1005,18 @@ void autofs_sasl_dispose(struct ldap_con
logmsg("krb5_cc_destroy failed with non-fatal error %d",
ret);
- status = pthread_mutex_unlock(&krb5cc_mutex);
- if (status)
- fatal(status);
-
krb5_free_context(ctxt->krb5ctxt);
if (unsetenv(krb5ccenv) != 0)
logerr("unsetenv failed with error %d", errno);
ctxt->krb5ctxt = NULL;
ctxt->krb5_ccache = NULL;
- ctxt->kinit_done = 0;
ctxt->kinit_successful = 0;
}
+
+ status = pthread_mutex_unlock(&krb5cc_mutex);
+ if (status)
+ fatal(status);
}
static void *sasl_mutex_new(void)

View File

@ -0,0 +1,132 @@
autofs-5.1.8 - always recreate credential cache
From: Ian Collier <imc@cs.ox.ac.uk>
In recent Kerberos revisions when a TGT expires autofs will fail to
renew the ticket.
Expired creds are being pulled out of the cache and in that case the patched
version clears the cache to remove the expired creds.
If the cache is already in use, try to pull out a cred and then if that
was successful and the cred is expired, clear the cache.
So this fixes the behaviour I was seeing, since that was happening because
expired creds were being pulled out of the cache and in that case the patched
version clears the cache to remove the expired creds.
What sort of race conditions might happen here?
- If the function is called very late during the validity of a ticket, it
might expire after the decision not to clear the cache. In that case,
the behaviour is the same as the unpatched version, but this is highly
unlikely because do_kinit is not supposed to happen while there is a
valid ticket.
- If two or more threads decide to call do_kinit at about the same time:
it's protected by a mutex, so one of the calls will happen first; this
call will clear the cache and add a new ticket. When the others kick
in, the cache won't be cleared because it's only cleared if we can
find an expired ticket in the cache and any such ticket was removed
when the first do_kinit happened.
- If one thread does do_kinit while another thread is trying to do a lookup:
if the current ticket is expired then the lookup would have failed anyway;
if it's not expired then we won't clear the cache.
- If there is both an expired and a valid ticket in the cache:
this only happens if two or more do_kinits clashed and stored tickets
with different expiration times, and if the current time is between those
times. The current bug happens because krb5 cache retrieval is returning
the earliest (i.e. expired) ticket. When that's the case then do_kinit
will clear the cache because when it tests the cache it will pull the
expired cred - and it needs to do this because otherwise all lookups are
failing (that's the bug). In a case where krb5 cache retrieval returns
the valid ticket, it doesn't matter that the cache is not cleared because
any subsequent lookups will use that valid ticket.
Signed-off-by: Ian Collier <imc@cs.ox.ac.uk>
---
CHANGELOG | 1
modules/cyrus-sasl.c | 53 +++++++++++++++++++++++++++++++++++++++------------
2 files changed, 42 insertions(+), 12 deletions(-)
--- autofs-5.1.4.orig/CHANGELOG
+++ autofs-5.1.4/CHANGELOG
@@ -163,6 +163,7 @@
- add flags argument to amd do_program_mount().
- fix deadlock in master_notify_submount().
- fix ldap sasl reconnect problem.
+- always recreate credential cache.
xx/xx/2018 autofs-5.1.5
- fix flag file permission.
--- autofs-5.1.4.orig/modules/cyrus-sasl.c
+++ autofs-5.1.4/modules/cyrus-sasl.c
@@ -509,6 +509,46 @@ sasl_do_kinit(unsigned logopt, struct lo
debug(logopt, "Using tgs name %s", tgs_name);
memset(&my_creds, 0, sizeof(my_creds));
+
+ if (krb5cc_in_use++ == 0) {
+ /* tell the cache what the default principal is */
+ ret = krb5_cc_initialize(ctxt->krb5ctxt,
+ ctxt->krb5_ccache, krb5_client_princ);
+
+ if (ret) {
+ --krb5cc_in_use;
+ error(logopt,
+ "krb5_cc_initialize failed with error %d", ret);
+ goto out_cleanup_unparse;
+ }
+ }
+ else {
+ krb5_creds match_creds, out_creds;
+ time_t now = monotonic_time(NULL);
+
+ /* even if the cache is in use, we will clear it if it
+ * contains an expired credential for our principal,
+ * because Kerberos doesn't always work well with caches
+ * that contain both expired and valid credentials
+ */
+ memset(&match_creds, 0, sizeof match_creds);
+ match_creds.client = krb5_client_princ;
+ match_creds.server = tgs_princ;
+ ret = krb5_cc_retrieve_cred(ctxt->krb5ctxt, ctxt->krb5_ccache,
+ 0, &match_creds, &out_creds);
+ if (ret == 0 && (time_t) out_creds.times.endtime < now) {
+ debug(logopt,
+ "calling krb5_cc_initialize to clear expired tickets");
+ ret = krb5_cc_initialize(ctxt->krb5ctxt,
+ ctxt->krb5_ccache, krb5_client_princ);
+ if (ret)
+ warn(logopt,
+ "krb5_cc_initialize failed with error %d "
+ "while trying to clear existing cache",
+ ret);
+ }
+ }
+
ret = krb5_get_init_creds_keytab(ctxt->krb5ctxt, &my_creds,
krb5_client_princ,
NULL /*keytab*/,
@@ -521,18 +561,7 @@ sasl_do_kinit(unsigned logopt, struct lo
goto out_cleanup_unparse;
}
- if (krb5cc_in_use++ == 0)
- /* tell the cache what the default principal is */
- ret = krb5_cc_initialize(ctxt->krb5ctxt,
- ctxt->krb5_ccache, krb5_client_princ);
-
- if (ret) {
- error(logopt,
- "krb5_cc_initialize failed with error %d", ret);
- goto out_cleanup_creds;
- }
-
- /* and store credentials for that principal */
+ /* and store credentials for our principal */
ret = krb5_cc_store_cred(ctxt->krb5ctxt, ctxt->krb5_ccache, &my_creds);
if (ret) {
error(logopt,

View File

@ -0,0 +1,36 @@
autofs-5.1.9 - fix always recreate credential cache
From: Ian Kent <raven@themaw.net>
When I aplied the original patch from Ian Collier for this I changed
the credential end time comparison to be against the time returned from
monotomic_time(). But this isn't the same as the calander time returned
from time() which Ian used in his original patch.
Signed-off-by: Ian Kent < raven@themaw.net>
---
CHANGELOG | 1 +
modules/cyrus-sasl.c | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
--- autofs-5.1.4.orig/CHANGELOG
+++ autofs-5.1.4/CHANGELOG
@@ -164,6 +164,7 @@
- fix deadlock in master_notify_submount().
- fix ldap sasl reconnect problem.
- always recreate credential cache.
+- fix always recreate credential cache.
xx/xx/2018 autofs-5.1.5
- fix flag file permission.
--- autofs-5.1.4.orig/modules/cyrus-sasl.c
+++ autofs-5.1.4/modules/cyrus-sasl.c
@@ -524,7 +524,7 @@ sasl_do_kinit(unsigned logopt, struct lo
}
else {
krb5_creds match_creds, out_creds;
- time_t now = monotonic_time(NULL);
+ time_t now = time(NULL);
/* even if the cache is in use, we will clear it if it
* contains an expired credential for our principal,

View File

@ -8,7 +8,7 @@
Summary: A tool for automatically mounting and unmounting filesystems
Name: autofs
Version: 5.1.4
Release: 114%{?dist}.3
Release: 114%{?dist}.4
Epoch: 1
License: GPLv2+
Group: System Environment/Daemons
@ -345,6 +345,11 @@ Patch338: autofs-5.1.9-fix-deadlock-in-master_notify_submount.patch
Patch339: autofs-5.1.9-fix-lock-ordering-deadlock-in-expire_cleanup.patch
# JIRA: RHEL-90238
Patch340: autofs-5.1.6-fix-ldap-sasl-reconnect-problem.patch
Patch341: autofs-5.1.8-always-recreate-credential-cache.patch
Patch342: autofs-5.1.9-fix-always-recreate-credential-cache.patch
%if %{with_systemd}
BuildRequires: systemd-units
BuildRequires: systemd-devel
@ -730,6 +735,10 @@ echo %{version}-%{release} > .version
%patch -P 339 -p1
%patch -P 340 -p1
%patch -P 341 -p1
%patch -P 342 -p1
%build
LDFLAGS=-Wl,-z,now
%configure --disable-mount-locking --enable-ignore-busy --with-libtirpc --without-hesiod %{?systemd_configure_arg:}
@ -824,6 +833,13 @@ fi
%dir /etc/auto.master.d
%changelog
* Mon Jun 09 2025 Ian Kent <ikent@redhat.com> - 5.1.4-114.el8_10.4
- RHEL-90238 - autofs fails to mount shares when using kerberised LDAP (RHEL 8)
- fix ldap sasl reconnect problem.
- always recreate credential cache.
- fix always recreate credential cache.
- Resolves: RHEL-90238
* Mon Apr 07 2025 Ian Kent <ikent@redhat.com> - 5.1.4-114.el8_10.3
- RHEL-84118 - autofs hang - autofs-5.1.4-114.el8_10.2
- fix lock ordering deadlock in expire_cleanup().