diff --git a/autofs-5.1.6-fix-ldap-sasl-reconnect-problem.patch b/autofs-5.1.6-fix-ldap-sasl-reconnect-problem.patch new file mode 100644 index 0000000..b9b2af5 --- /dev/null +++ b/autofs-5.1.6-fix-ldap-sasl-reconnect-problem.patch @@ -0,0 +1,347 @@ +autofs-5.1.6 - fix ldap sasl reconnect problem + +From: Ian Kent + +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 +--- + 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) diff --git a/autofs-5.1.8-always-recreate-credential-cache.patch b/autofs-5.1.8-always-recreate-credential-cache.patch new file mode 100644 index 0000000..1f6d7b6 --- /dev/null +++ b/autofs-5.1.8-always-recreate-credential-cache.patch @@ -0,0 +1,132 @@ +autofs-5.1.8 - always recreate credential cache + +From: Ian Collier + +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 +--- + 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, diff --git a/autofs-5.1.9-fix-always-recreate-credential-cache.patch b/autofs-5.1.9-fix-always-recreate-credential-cache.patch new file mode 100644 index 0000000..b688e58 --- /dev/null +++ b/autofs-5.1.9-fix-always-recreate-credential-cache.patch @@ -0,0 +1,36 @@ +autofs-5.1.9 - fix always recreate credential cache + +From: Ian Kent + +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, diff --git a/autofs.spec b/autofs.spec index fe26822..d2736f6 100644 --- a/autofs.spec +++ b/autofs.spec @@ -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 - 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 - 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().