From 60a20d015605996b4aaaa75098bee929d867be7e Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Oct 12 2021 13:24:29 +0000 Subject: import nfs-utils-1.3.0-0.68.el7.2 --- diff --git a/SOURCES/nfs-utils-1.3.0-gssd-mutex-updated.patch b/SOURCES/nfs-utils-1.3.0-gssd-mutex-updated.patch new file mode 100644 index 0000000..7073633 --- /dev/null +++ b/SOURCES/nfs-utils-1.3.0-gssd-mutex-updated.patch @@ -0,0 +1,784 @@ +diff --git a/utils/gssd/gssd.c b/utils/gssd/gssd.c +index c5b5dc9..1f85c71 100644 +--- a/utils/gssd/gssd.c ++++ b/utils/gssd/gssd.c +@@ -90,9 +90,8 @@ char *preferred_realm = NULL; + char *ccachedir = NULL; + /* Avoid DNS reverse lookups on server names */ + static bool avoid_dns = true; +-int thread_started = false; +-pthread_mutex_t pmutex = PTHREAD_MUTEX_INITIALIZER; +-pthread_cond_t pcond = PTHREAD_COND_INITIALIZER; ++pthread_mutex_t clp_lock = PTHREAD_MUTEX_INITIALIZER; ++static bool signal_received = false; + + TAILQ_HEAD(topdir_list_head, topdir) topdir_list; + +@@ -359,20 +358,28 @@ out: + free(port); + } + ++/* Actually frees clp and fields that might be used from other ++ * threads if was last reference. ++ */ + static void +-gssd_destroy_client(struct clnt_info *clp) ++gssd_free_client(struct clnt_info *clp) + { +- if (clp->krb5_fd >= 0) { ++ int refcnt; ++ ++ pthread_mutex_lock(&clp_lock); ++ refcnt = --clp->refcount; ++ pthread_mutex_unlock(&clp_lock); ++ if (refcnt > 0) ++ return; ++ ++ printerr(3, "freeing client %s\n", clp->relpath); ++ ++ if (clp->krb5_fd >= 0) + close(clp->krb5_fd); +- event_del(&clp->krb5_ev); +- } + +- if (clp->gssd_fd >= 0) { ++ if (clp->gssd_fd >= 0) + close(clp->gssd_fd); +- event_del(&clp->gssd_ev); +- } + +- inotify_rm_watch(inotify_fd, clp->wd); + free(clp->relpath); + free(clp->servicename); + free(clp->servername); +@@ -380,6 +387,24 @@ gssd_destroy_client(struct clnt_info *clp) + free(clp); + } + ++/* Called when removing from clnt_list to tear down event handling. ++ * Will then free clp if was last reference. ++ */ ++static void ++gssd_destroy_client(struct clnt_info *clp) ++{ ++ printerr(3, "destroying client %s\n", clp->relpath); ++ ++ if (clp->krb5_fd >= 0) ++ event_del(&clp->krb5_ev); ++ ++ if (clp->gssd_fd >= 0) ++ event_del(&clp->gssd_ev); ++ ++ inotify_rm_watch(inotify_fd, clp->wd); ++ gssd_free_client(clp); ++} ++ + static void gssd_scan(void); + + static int +@@ -416,11 +441,21 @@ static struct clnt_upcall_info *alloc_upcall_info(struct clnt_info *clp) + info = malloc(sizeof(struct clnt_upcall_info)); + if (info == NULL) + return NULL; ++ ++ pthread_mutex_lock(&clp_lock); ++ clp->refcount++; ++ pthread_mutex_unlock(&clp_lock); + info->clp = clp; + + return info; + } + ++void free_upcall_info(struct clnt_upcall_info *info) ++{ ++ gssd_free_client(info->clp); ++ free(info); ++} ++ + /* For each upcall read the upcall info into the buffer, then create a + * thread in a detached state so that resources are released back into + * the system without the need for a join. +@@ -438,13 +473,13 @@ gssd_clnt_gssd_cb(int UNUSED(fd), short UNUSED(which), void *data) + info->lbuflen = read(clp->gssd_fd, info->lbuf, sizeof(info->lbuf)); + if (info->lbuflen <= 0 || info->lbuf[info->lbuflen-1] != '\n') { + printerr(0, "WARNING: %s: failed reading request\n", __func__); +- free(info); ++ free_upcall_info(info); + return; + } + info->lbuf[info->lbuflen-1] = 0; + + if (start_upcall_thread(handle_gssd_upcall, info)) +- free(info); ++ free_upcall_info(info); + } + + static void +@@ -461,12 +496,12 @@ gssd_clnt_krb5_cb(int UNUSED(fd), short UNUSED(which), void *data) + sizeof(info->uid)) < (ssize_t)sizeof(info->uid)) { + printerr(0, "WARNING: %s: failed reading uid from krb5 " + "upcall pipe: %s\n", __func__, strerror(errno)); +- free(info); ++ free_upcall_info(info); + return; + } + + if (start_upcall_thread(handle_krb5_upcall, info)) +- free(info); ++ free_upcall_info(info); + } + + static struct clnt_info * +@@ -501,6 +536,7 @@ gssd_get_clnt(struct topdir *tdi, const char *name) + clp->name = clp->relpath + strlen(tdi->name) + 1; + clp->krb5_fd = -1; + clp->gssd_fd = -1; ++ clp->refcount = 1; + + TAILQ_INSERT_HEAD(&tdi->clnt_list, clp, list); + return clp; +@@ -649,7 +685,7 @@ gssd_scan_topdir(const char *name) + if (clp->scanned) + continue; + +- printerr(3, "destroying client %s\n", clp->relpath); ++ printerr(3, "orphaned client %s\n", clp->relpath); + saveprev = clp->list.tqe_prev; + TAILQ_REMOVE(&tdi->clnt_list, clp, list); + gssd_destroy_client(clp); +@@ -824,8 +860,13 @@ found: + static void + sig_die(int signal) + { +- if (root_uses_machine_creds) +- gssd_destroy_krb5_machine_creds(); ++ if (signal_received) { ++ gssd_destroy_krb5_principals(root_uses_machine_creds); ++ printerr(1, "forced exiting on signal %d\n", signal); ++ exit(0); ++ } ++ ++ signal_received = true; + printerr(1, "exiting on signal %d\n", signal); + exit(0); + } +@@ -883,6 +924,7 @@ main(int argc, char *argv[]) + int rpc_verbosity = 0; + int opt; + int i; ++ int rc; + extern char *optarg; + char *progname; + struct event sighup_ev; +@@ -1054,7 +1096,30 @@ main(int argc, char *argv[]) + + event_dispatch(); + +- printerr(0, "ERROR: event_dispatch() returned!\n"); +- return EXIT_FAILURE; +-} ++ printerr(0, "event_dispatch() returned %i!\n", rc); ++ ++ gssd_destroy_krb5_principals(root_uses_machine_creds); ++ ++ while (!TAILQ_EMPTY(&topdir_list)) { ++ struct topdir *tdi = TAILQ_FIRST(&topdir_list); ++ TAILQ_REMOVE(&topdir_list, tdi, list); ++ while (!TAILQ_EMPTY(&tdi->clnt_list)) { ++ struct clnt_info *clp = TAILQ_FIRST(&tdi->clnt_list); ++ TAILQ_REMOVE(&tdi->clnt_list, clp, list); ++ gssd_destroy_client(clp); ++ } ++ free(tdi); ++ } ++ ++ event_del(&inotify_ev); ++ signal_del(&sighup_ev); ++ ++ close(inotify_fd); ++ close(pipefs_fd); ++ closedir(pipefs_dir); + ++ free(preferred_realm); ++ free(ccachesearch); ++ ++ return rc < 0 ? EXIT_FAILURE : EXIT_SUCCESS; ++} +diff --git a/utils/gssd/gssd.h b/utils/gssd/gssd.h +index f4f5975..5091df6 100644 +--- a/utils/gssd/gssd.h ++++ b/utils/gssd/gssd.h +@@ -62,13 +62,10 @@ extern int root_uses_machine_creds; + extern unsigned int context_timeout; + extern unsigned int rpc_timeout; + extern char *preferred_realm; +-extern pthread_mutex_t ple_lock; +-extern pthread_cond_t pcond; +-extern pthread_mutex_t pmutex; +-extern int thread_started; + + struct clnt_info { + TAILQ_ENTRY(clnt_info) list; ++ int refcount; + int wd; + bool scanned; + char *name; +@@ -94,6 +91,7 @@ struct clnt_upcall_info { + + void handle_krb5_upcall(struct clnt_upcall_info *clp); + void handle_gssd_upcall(struct clnt_upcall_info *clp); ++void free_upcall_info(struct clnt_upcall_info *info); + + + #endif /* _RPC_GSSD_H_ */ +diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c +index 504c398..f34dffa 100644 +--- a/utils/gssd/gssd_proc.c ++++ b/utils/gssd/gssd_proc.c +@@ -543,7 +543,7 @@ krb5_use_machine_creds(struct clnt_info *clp, uid_t uid, char *tgtname, + uid, tgtname); + + do { +- gssd_refresh_krb5_machine_credential(clp->servername, NULL, ++ gssd_refresh_krb5_machine_credential(clp->servername, + service); + /* + * Get a list of credential cache names and try each +@@ -724,7 +724,7 @@ handle_krb5_upcall(struct clnt_upcall_info *info) + printerr(2, "\n%s: uid %d (%s)\n", __func__, info->uid, clp->relpath); + + process_krb5_upcall(clp, info->uid, clp->krb5_fd, NULL, NULL); +- free(info); ++ free_upcall_info(info); + } + + void +@@ -821,7 +821,7 @@ handle_gssd_upcall(struct clnt_upcall_info *info) + out: + free(upcall_str); + out_nomem: +- free(info); ++ free_upcall_info(info); + return; + } + +diff --git a/utils/gssd/krb5_util.c b/utils/gssd/krb5_util.c +index 3fb11e1..f05ebfd 100644 +--- a/utils/gssd/krb5_util.c ++++ b/utils/gssd/krb5_util.c +@@ -126,9 +126,28 @@ + #include "gss_util.h" + #include "krb5_util.h" + ++/* ++ * List of principals from our keytab that we ++ * will try to use to obtain credentials ++ * (known as a principal list entry (ple)) ++ */ ++struct gssd_k5_kt_princ { ++ struct gssd_k5_kt_princ *next; ++ // Only protect against deletion, not modification ++ int refcount; ++ // Only set during creation in new_ple() ++ krb5_principal princ; ++ char *realm; ++ // Modified during usage by gssd_get_single_krb5_cred() ++ char *ccname; ++ krb5_timestamp endtime; ++}; ++ ++ + /* Global list of principals/cache file names for machine credentials */ +-struct gssd_k5_kt_princ *gssd_k5_kt_princ_list = NULL; +-pthread_mutex_t ple_lock = PTHREAD_MUTEX_INITIALIZER; ++static struct gssd_k5_kt_princ *gssd_k5_kt_princ_list = NULL; ++/* This mutex protects list modification & ple->ccname */ ++static pthread_mutex_t ple_lock = PTHREAD_MUTEX_INITIALIZER; + + #ifdef HAVE_SET_ALLOWABLE_ENCTYPES + int limit_to_legacy_enctypes = 0; +@@ -146,6 +165,28 @@ static int gssd_get_single_krb5_cred(krb5_context context, + static int query_krb5_ccache(const char* cred_cache, char **ret_princname, + char **ret_realm); + ++static void release_ple_locked(krb5_context context, ++ struct gssd_k5_kt_princ *ple) ++{ ++ if (--ple->refcount) ++ return; ++ ++ printerr(3, "freeing cached principal (ccname=%s, realm=%s)\n", ++ ple->ccname, ple->realm); ++ krb5_free_principal(context, ple->princ); ++ free(ple->ccname); ++ free(ple->realm); ++ free(ple); ++} ++ ++static void release_ple(krb5_context context, struct gssd_k5_kt_princ *ple) ++{ ++ pthread_mutex_lock(&ple_lock); ++ release_ple_locked(context, ple); ++ pthread_mutex_unlock(&ple_lock); ++} ++ ++ + /* + * Called from the scandir function to weed out potential krb5 + * credentials cache files +@@ -356,12 +397,15 @@ gssd_get_single_krb5_cred(krb5_context context, + * 300 because clock skew must be within 300sec for kerberos + */ + now += 300; ++ pthread_mutex_lock(&ple_lock); + if (ple->ccname && ple->endtime > now && !nocache) { + printerr(3, "INFO: Credentials in CC '%s' are good until %d\n", + ple->ccname, ple->endtime); + code = 0; ++ pthread_mutex_unlock(&ple_lock); + goto out; + } ++ pthread_mutex_unlock(&ple_lock); + + if ((code = krb5_kt_get_name(context, kt, kt_name, BUFSIZ))) { + printerr(0, "ERROR: Unable to get keytab name in " +@@ -414,6 +458,7 @@ gssd_get_single_krb5_cred(krb5_context context, + * Initialize cache file which we're going to be using + */ + ++ pthread_mutex_lock(&ple_lock); + if (use_memcache) + cache_type = "MEMORY"; + else +@@ -423,15 +468,18 @@ gssd_get_single_krb5_cred(krb5_context context, + ccachesearch[0], GSSD_DEFAULT_CRED_PREFIX, + GSSD_DEFAULT_MACHINE_CRED_SUFFIX, ple->realm); + ple->endtime = my_creds.times.endtime; +- if (ple->ccname != NULL) ++ if (ple->ccname == NULL || strcmp(ple->ccname, cc_name) != 0) { + free(ple->ccname); +- ple->ccname = strdup(cc_name); +- if (ple->ccname == NULL) { +- printerr(0, "ERROR: no storage to duplicate credentials " +- "cache name '%s'\n", cc_name); +- code = ENOMEM; +- goto out; ++ ple->ccname = strdup(cc_name); ++ if (ple->ccname == NULL) { ++ printerr(0, "ERROR: no storage to duplicate credentials " ++ "cache name '%s'\n", cc_name); ++ code = ENOMEM; ++ pthread_mutex_unlock(&ple_lock); ++ goto out; ++ } + } ++ pthread_mutex_unlock(&ple_lock); + if ((code = krb5_cc_resolve(context, cc_name, &ccache))) { + k5err = gssd_k5_err_msg(context, code); + printerr(0, "ERROR: %s while opening credential cache '%s'\n", +@@ -469,6 +517,7 @@ gssd_get_single_krb5_cred(krb5_context context, + + /* + * Given a principal, find a matching ple structure ++ * Called with mutex held + */ + static struct gssd_k5_kt_princ * + find_ple_by_princ(krb5_context context, krb5_principal princ) +@@ -485,6 +534,7 @@ find_ple_by_princ(krb5_context context, krb5_principal princ) + + /* + * Create, initialize, and add a new ple structure to the global list ++ * Called with mutex held + */ + static struct gssd_k5_kt_princ * + new_ple(krb5_context context, krb5_principal princ) +@@ -536,6 +586,7 @@ new_ple(krb5_context context, krb5_principal princ) + p->next = ple; + } + ++ ple->refcount = 1; + return ple; + outerr: + if (ple) { +@@ -554,13 +605,14 @@ get_ple_by_princ(krb5_context context, krb5_principal princ) + { + struct gssd_k5_kt_princ *ple; + +- /* Need to serialize list if we ever become multi-threaded! */ +- + pthread_mutex_lock(&ple_lock); + ple = find_ple_by_princ(context, princ); + if (ple == NULL) { + ple = new_ple(context, princ); + } ++ if (ple != NULL) { ++ ple->refcount++; ++ } + pthread_mutex_unlock(&ple_lock); + + return ple; +@@ -725,6 +777,8 @@ gssd_search_krb5_keytab(krb5_context context, krb5_keytab kt, + retval = ENOMEM; + k5_free_kt_entry(context, kte); + } else { ++ release_ple(context, ple); ++ ple = NULL; + retval = 0; + *found = 1; + } +@@ -1052,6 +1106,93 @@ err_cache: + return found; + } + ++/* ++ * Obtain (or refresh if necessary) Kerberos machine credentials ++ * If a ple is passed in, it's reference will be released ++ */ ++static int ++gssd_refresh_krb5_machine_credential_internal(char *hostname, ++ struct gssd_k5_kt_princ *ple, ++ char *service) ++{ ++ krb5_error_code code = 0; ++ krb5_context context; ++ krb5_keytab kt = NULL;; ++ int retval = 0; ++ char *k5err = NULL; ++ const char *svcnames[] = { "$", "root", "nfs", "host", NULL }; ++ ++ printerr(2, "%s: hostname=%s ple=%p service=%s \n", ++ __func__, hostname, ple, service); ++ ++ /* ++ * If a specific service name was specified, use it. ++ * Otherwise, use the default list. ++ */ ++ if (service != NULL && strcmp(service, "*") != 0) { ++ svcnames[0] = service; ++ svcnames[1] = NULL; ++ } ++ if (hostname == NULL && ple == NULL) ++ return EINVAL; ++ ++ code = krb5_init_context(&context); ++ if (code) { ++ k5err = gssd_k5_err_msg(NULL, code); ++ printerr(0, "ERROR: %s: %s while initializing krb5 context\n", ++ __func__, k5err); ++ retval = code; ++ goto out; ++ } ++ ++ if ((code = krb5_kt_resolve(context, keytabfile, &kt))) { ++ k5err = gssd_k5_err_msg(context, code); ++ printerr(0, "ERROR: %s: %s while resolving keytab '%s'\n", ++ __func__, k5err, keytabfile); ++ goto out_free_context; ++ } ++ ++ if (ple == NULL) { ++ krb5_keytab_entry kte; ++ ++ code = find_keytab_entry(context, kt, hostname, ++ &kte, svcnames); ++ if (code) { ++ printerr(0, "ERROR: %s: no usable keytab entry found " ++ "in keytab %s for connection with host %s\n", ++ __FUNCTION__, keytabfile, hostname); ++ retval = code; ++ goto out_free_kt; ++ } ++ ++ ple = get_ple_by_princ(context, kte.principal); ++ k5_free_kt_entry(context, &kte); ++ if (ple == NULL) { ++ char *pname; ++ if ((krb5_unparse_name(context, kte.principal, &pname))) { ++ pname = NULL; ++ } ++ printerr(0, "ERROR: %s: Could not locate or create " ++ "ple struct for principal %s for connection " ++ "with host %s\n", ++ __FUNCTION__, pname ? pname : "", ++ hostname); ++ if (pname) k5_free_unparsed_name(context, pname); ++ goto out_free_kt; ++ } ++ } ++ retval = gssd_get_single_krb5_cred(context, kt, ple, 0); ++out_free_kt: ++ krb5_kt_close(context, kt); ++out_free_context: ++ if (ple) ++ release_ple(context, ple); ++ krb5_free_context(context); ++out: ++ free(k5err); ++ return retval; ++} ++ + /*==========================*/ + /*=== External routines ===*/ + /*==========================*/ +@@ -1145,37 +1286,56 @@ gssd_get_krb5_machine_cred_list(char ***list) + goto out; + } + +- /* Need to serialize list if we ever become multi-threaded! */ +- ++ pthread_mutex_lock(&ple_lock); + for (ple = gssd_k5_kt_princ_list; ple; ple = ple->next) { +- if (ple->ccname) { +- /* Make sure cred is up-to-date before returning it */ +- retval = gssd_refresh_krb5_machine_credential(NULL, ple, +- NULL); +- if (retval) +- continue; +- if (i + 1 > listsize) { +- listsize += listinc; +- l = (char **) +- realloc(l, listsize * sizeof(char *)); +- if (l == NULL) { +- retval = ENOMEM; +- goto out; +- } +- } +- if ((l[i++] = strdup(ple->ccname)) == NULL) { ++ if (!ple->ccname) ++ continue; ++ ++ /* Take advantage of the fact we only remove the ple ++ * from the list during shutdown. If it's modified ++ * concurrently at worst we'll just miss a new entry ++ * before the current ple ++ * ++ * gssd_refresh_krb5_machine_credential_internal() will ++ * release the ple refcount ++ */ ++ ple->refcount++; ++ pthread_mutex_unlock(&ple_lock); ++ /* Make sure cred is up-to-date before returning it */ ++ retval = gssd_refresh_krb5_machine_credential_internal(NULL, ple, ++ NULL); ++ pthread_mutex_lock(&ple_lock); ++ if (gssd_k5_kt_princ_list == NULL) { ++ /* Looks like we did shutdown... abort */ ++ l[i] = NULL; ++ gssd_free_krb5_machine_cred_list(l); ++ retval = ENOMEM; ++ goto out_lock; ++ } ++ if (retval) ++ continue; ++ if (i + 1 > listsize) { ++ listsize += listinc; ++ l = (char **) ++ realloc(l, listsize * sizeof(char *)); ++ if (l == NULL) { + retval = ENOMEM; +- goto out; ++ goto out_lock; + } + } ++ if ((l[i++] = strdup(ple->ccname)) == NULL) { ++ retval = ENOMEM; ++ goto out_lock; ++ } + } + if (i > 0) { + l[i] = NULL; + *list = l; + retval = 0; +- goto out; + } else + free((void *)l); ++out_lock: ++ pthread_mutex_unlock(&ple_lock); + out: + return retval; + } +@@ -1200,7 +1360,7 @@ gssd_free_krb5_machine_cred_list(char **list) + * Called upon exit. Destroys machine credentials. + */ + void +-gssd_destroy_krb5_machine_creds(void) ++gssd_destroy_krb5_principals(int destroy_machine_creds) + { + krb5_context context; + krb5_error_code code = 0; +@@ -1212,113 +1372,48 @@ gssd_destroy_krb5_machine_creds(void) + if (code) { + k5err = gssd_k5_err_msg(NULL, code); + printerr(0, "ERROR: %s while initializing krb5\n", k5err); +- goto out; ++ free(k5err); ++ return; + } + +- for (ple = gssd_k5_kt_princ_list; ple; ple = ple->next) { +- if (!ple->ccname) +- continue; +- if ((code = krb5_cc_resolve(context, ple->ccname, &ccache))) { +- k5err = gssd_k5_err_msg(context, code); +- printerr(0, "WARNING: %s while resolving credential " +- "cache '%s' for destruction\n", k5err, +- ple->ccname); +- free(k5err); +- k5err = NULL; +- continue; +- } ++ pthread_mutex_lock(&ple_lock); ++ while (gssd_k5_kt_princ_list) { ++ ple = gssd_k5_kt_princ_list; ++ gssd_k5_kt_princ_list = ple->next; + +- if ((code = krb5_cc_destroy(context, ccache))) { +- k5err = gssd_k5_err_msg(context, code); +- printerr(0, "WARNING: %s while destroying credential " +- "cache '%s'\n", k5err, ple->ccname); +- free(k5err); +- k5err = NULL; ++ if (destroy_machine_creds && ple->ccname) { ++ if ((code = krb5_cc_resolve(context, ple->ccname, &ccache))) { ++ k5err = gssd_k5_err_msg(context, code); ++ printerr(0, "WARNING: %s while resolving credential " ++ "cache '%s' for destruction\n", k5err, ++ ple->ccname); ++ free(k5err); ++ k5err = NULL; ++ } ++ ++ if (!code && (code = krb5_cc_destroy(context, ccache))) { ++ k5err = gssd_k5_err_msg(context, code); ++ printerr(0, "WARNING: %s while destroying credential " ++ "cache '%s'\n", k5err, ple->ccname); ++ free(k5err); ++ k5err = NULL; ++ } + } ++ ++ release_ple_locked(context, ple); + } ++ pthread_mutex_unlock(&ple_lock); + krb5_free_context(context); +- out: +- free(k5err); + } + + /* + * Obtain (or refresh if necessary) Kerberos machine credentials + */ + int +-gssd_refresh_krb5_machine_credential(char *hostname, +- struct gssd_k5_kt_princ *ple, +- char *service) ++gssd_refresh_krb5_machine_credential(char *hostname, char *service) + { +- krb5_error_code code = 0; +- krb5_context context; +- krb5_keytab kt = NULL;; +- int retval = 0; +- char *k5err = NULL; +- const char *svcnames[] = { "$", "root", "nfs", "host", NULL }; +- +- /* +- * If a specific service name was specified, use it. +- * Otherwise, use the default list. +- */ +- if (service != NULL && strcmp(service, "*") != 0) { +- svcnames[0] = service; +- svcnames[1] = NULL; +- } +- if (hostname == NULL && ple == NULL) +- return EINVAL; +- +- code = krb5_init_context(&context); +- if (code) { +- k5err = gssd_k5_err_msg(NULL, code); +- printerr(0, "ERROR: %s: %s while initializing krb5 context\n", +- __func__, k5err); +- retval = code; +- goto out; +- } +- +- if ((code = krb5_kt_resolve(context, keytabfile, &kt))) { +- k5err = gssd_k5_err_msg(context, code); +- printerr(0, "ERROR: %s: %s while resolving keytab '%s'\n", +- __func__, k5err, keytabfile); +- goto out_free_context; +- } +- +- if (ple == NULL) { +- krb5_keytab_entry kte; +- +- code = find_keytab_entry(context, kt, hostname, &kte, svcnames); +- if (code) { +- printerr(0, "ERROR: %s: no usable keytab entry found " +- "in keytab %s for connection with host %s\n", +- __FUNCTION__, keytabfile, hostname); +- retval = code; +- goto out_free_kt; +- } +- +- ple = get_ple_by_princ(context, kte.principal); +- k5_free_kt_entry(context, &kte); +- if (ple == NULL) { +- char *pname; +- if ((krb5_unparse_name(context, kte.principal, &pname))) { +- pname = NULL; +- } +- printerr(0, "ERROR: %s: Could not locate or create " +- "ple struct for principal %s for connection " +- "with host %s\n", +- __FUNCTION__, pname ? pname : "", +- hostname); +- if (pname) k5_free_unparsed_name(context, pname); +- goto out_free_kt; +- } +- } +- retval = gssd_get_single_krb5_cred(context, kt, ple, 0); +-out_free_kt: +- krb5_kt_close(context, kt); +-out_free_context: +- krb5_free_context(context); +-out: +- free(k5err); +- return retval; ++ return gssd_refresh_krb5_machine_credential_internal(hostname, NULL, ++ service); + } + + /* +diff --git a/utils/gssd/krb5_util.h b/utils/gssd/krb5_util.h +index e3bbb07..b38c7d5 100644 +--- a/utils/gssd/krb5_util.h ++++ b/utils/gssd/krb5_util.h +@@ -9,27 +9,13 @@ + #include "gss_oids.h" + #endif + +-/* +- * List of principals from our keytab that we +- * will try to use to obtain credentials +- * (known as a principal list entry (ple)) +- */ +-struct gssd_k5_kt_princ { +- struct gssd_k5_kt_princ *next; +- krb5_principal princ; +- char *ccname; +- char *realm; +- krb5_timestamp endtime; +-}; +- + + int gssd_setup_krb5_user_gss_ccache(uid_t uid, char *servername, + char *dirname); + int gssd_get_krb5_machine_cred_list(char ***list); + void gssd_free_krb5_machine_cred_list(char **list); +-void gssd_destroy_krb5_machine_creds(void); ++void gssd_destroy_krb5_principals(int destroy_machine_creds); + int gssd_refresh_krb5_machine_credential(char *hostname, +- struct gssd_k5_kt_princ *ple, + char *service); + char *gssd_k5_err_msg(krb5_context context, krb5_error_code code); + void gssd_k5_get_default_realm(char **def_realm); diff --git a/SPECS/nfs-utils.spec b/SPECS/nfs-utils.spec index 1a77331..4851220 100644 --- a/SPECS/nfs-utils.spec +++ b/SPECS/nfs-utils.spec @@ -2,7 +2,7 @@ Summary: NFS utilities and supporting clients and daemons for the kernel NFS ser Name: nfs-utils URL: http://sourceforge.net/projects/nfs Version: 1.3.0 -Release: 0.68%{?dist}.1 +Release: 0.68%{?dist}.2 Epoch: 1 # group all 32bit related archs @@ -172,6 +172,7 @@ Patch128: nfs-utils-1.3.0-rpcgssd-closedir.patch # RHEL7.9.z # Patch129: nfs-utils-1.3.0-exportfs-root.patch +Patch130: nfs-utils-1.3.0-gssd-mutex-updated.patch Patch1000: nfs-utils-1.2.1-statdpath-man.patch Patch1001: nfs-utils-1.2.1-exp-subtree-warn-off.patch @@ -487,6 +488,7 @@ This package also contains the mount.nfs and umount.nfs program. %patch128 -p1 # 1958975 - exportfs: unable to unexport root %patch129 -p1 +%patch130 -p1 %patch1000 -p1 %patch1001 -p1 @@ -739,6 +741,9 @@ fi /sbin/umount.nfs4 %changelog +* Tue Aug 10 2021 Steve Dickson 1.3.0-0.68.2 +- gssd: mutex updates (bz 1990981) + * Wed Jun 9 2020 Steve Dickson 1.3.0-0.68.1 - exportfs: fix unexporting of '/' (bz 1958975)