From 73ac723d858c137f9be6c6931f2638c49518c37f Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: May 18 2021 06:39:48 +0000 Subject: import nfs-utils-2.3.3-41.el8 --- diff --git a/SOURCES/nfs-utils-2.3.1-systemd-gssproxy-restart.patch b/SOURCES/nfs-utils-2.3.1-systemd-gssproxy-restart.patch index 60762e8..f298b89 100644 --- a/SOURCES/nfs-utils-2.3.1-systemd-gssproxy-restart.patch +++ b/SOURCES/nfs-utils-2.3.1-systemd-gssproxy-restart.patch @@ -1,9 +1,9 @@ -diff -up nfs-utils-2.3.1/systemd/nfs-server.service.orig nfs-utils-2.3.1/systemd/nfs-server.service ---- nfs-utils-2.3.1/systemd/nfs-server.service.orig 2018-01-19 10:25:38.153513857 -0500 -+++ nfs-utils-2.3.1/systemd/nfs-server.service 2018-01-19 10:30:52.977245126 -0500 -@@ -26,6 +26,7 @@ Type=oneshot +diff -up nfs-utils-2.3.3/systemd/nfs-server.service.orig nfs-utils-2.3.3/systemd/nfs-server.service +--- nfs-utils-2.3.3/systemd/nfs-server.service.orig 2020-12-11 09:05:23.499222371 -0500 ++++ nfs-utils-2.3.3/systemd/nfs-server.service 2020-12-11 09:06:38.970186395 -0500 +@@ -23,6 +23,7 @@ Type=oneshot RemainAfterExit=yes - ExecStartPre=/usr/sbin/exportfs -r + ExecStartPre=-/usr/sbin/exportfs -r ExecStart=/usr/sbin/rpc.nfsd +ExecStart=-/bin/sh -c 'if systemctl -q is-active gssproxy; then systemctl reload gssproxy ; fi' ExecStop=/usr/sbin/rpc.nfsd 0 diff --git a/SOURCES/nfs-utils-2.3.3-exportfs-man-labels.patch b/SOURCES/nfs-utils-2.3.3-exportfs-man-labels.patch new file mode 100644 index 0000000..738fb85 --- /dev/null +++ b/SOURCES/nfs-utils-2.3.3-exportfs-man-labels.patch @@ -0,0 +1,50 @@ +commit 7d5dcd2358df55353eed94a0e84b77bb3597634e +Author: J. Bruce Fields +Date: Fri Mar 27 13:11:28 2020 -0400 + + exports man page: warn about subdirectory exports + + Subdirectory exports have a number of problems which have been poorly + documented. + + Signed-off-by: J. Bruce Fields + Signed-off-by: Steve Dickson + +diff --git a/utils/exportfs/exports.man b/utils/exportfs/exports.man +index e3a16f6b..1d171849 100644 +--- a/utils/exportfs/exports.man ++++ b/utils/exportfs/exports.man +@@ -494,6 +494,33 @@ export entry for + .B /home/joe + in the example section below, which maps all requests to uid 150 (which + is supposedly that of user joe). ++ ++.SS Subdirectory Exports ++ ++Normally you should only export only the root of a filesystem. The NFS ++server will also allow you to export a subdirectory of a filesystem, ++however, this has drawbacks: ++ ++First, it may be possible for a malicious user to access files on the ++filesystem outside of the exported subdirectory, by guessing filehandles ++for those other files. The only way to prevent this is by using the ++.IR no_subtree_check ++option, which can cause other problems. ++ ++Second, export options may not be enforced in the way that you would ++expect. For example, the ++.IR security_label ++option will not work on subdirectory exports, and if nested subdirectory ++exports change the ++.IR security_label ++or ++.IR sec= ++options, NFSv4 clients will normally see only the options on the parent ++export. Also, where security options differ, a malicious client may use ++filehandle-guessing attacks to access the files from one subdirectory ++using the options from another. ++ ++ + .SS Extra Export Tables + After reading + .I /etc/exports diff --git a/SOURCES/nfs-utils-2.3.3-exports-manpage-outdated.patch b/SOURCES/nfs-utils-2.3.3-exports-manpage-outdated.patch new file mode 100644 index 0000000..1660781 --- /dev/null +++ b/SOURCES/nfs-utils-2.3.3-exports-manpage-outdated.patch @@ -0,0 +1,30 @@ +commit ba90d61be3abca5a699765ce08759ca6b986781d +Author: Steve Dickson +Date: Thu Dec 10 14:05:23 2020 -0500 + + exports.man: Remove some outdated verbiage + + Years ago, commit 6a7d90cea765 removed the warning + this verbiage was talking about, but was never + removed from the man page. + + Signed-off-by: Steve Dickson + +diff --git a/utils/exportfs/exports.man b/utils/exportfs/exports.man +index 1d171849..54b3f877 100644 +--- a/utils/exportfs/exports.man ++++ b/utils/exportfs/exports.man +@@ -169,13 +169,6 @@ default. In all releases after 1.0.0, + is the default, and + .I async + must be explicitly requested if needed. +-To help make system administrators aware of this change, +-.B exportfs +-will issue a warning if neither +-.I sync +-nor +-.I async +-is specified. + .TP + .IR no_wdelay + This option has no effect if diff --git a/SOURCES/nfs-utils-2.3.3-gssd-multithread-updates.patch b/SOURCES/nfs-utils-2.3.3-gssd-multithread-updates.patch new file mode 100644 index 0000000..2813d0c --- /dev/null +++ b/SOURCES/nfs-utils-2.3.3-gssd-multithread-updates.patch @@ -0,0 +1,1009 @@ +diff --git a/aclocal/libevent.m4 b/aclocal/libevent.m4 +index b5ac00ff..0ebcb524 100644 +--- a/aclocal/libevent.m4 ++++ b/aclocal/libevent.m4 +@@ -4,9 +4,13 @@ AC_DEFUN([AC_LIBEVENT], [ + dnl Check for libevent, but do not add -levent to LIBS + AC_CHECK_LIB([event], [event_dispatch], [LIBEVENT=-levent], + [AC_MSG_ERROR([libevent not found.])]) ++ AC_CHECK_LIB([event_core], [event_base_dispatch], [LIBEVENT=-levent_core], ++ [AC_MSG_ERROR([libevent2 not found.])]) + AC_SUBST(LIBEVENT) + + AC_CHECK_HEADERS([event.h], , + [AC_MSG_ERROR([libevent headers not found.])]) ++ AC_CHECK_HEADERS([event2/event.h], , ++ [AC_MSG_ERROR([libevent headers not found.])]) + + ])dnl +diff --git a/utils/gssd/gss_names.c b/utils/gssd/gss_names.c +index 2a7f3a13..982b96f4 100644 +--- a/utils/gssd/gss_names.c ++++ b/utils/gssd/gss_names.c +@@ -110,10 +110,12 @@ get_hostbased_client_name(gss_name_t client_name, gss_OID mech, + /* For Kerberos, transform the NT_KRB5_PRINCIPAL name to + * an NT_HOSTBASED_SERVICE name */ + if (g_OID_equal(&krb5oid, mech)) { +- if (get_krb5_hostbased_name(&name, &cname) == 0) +- *hostbased_name = cname; ++ if (get_krb5_hostbased_name(&name, &cname) != 0) ++ goto out_rel_buf; ++ *hostbased_name = cname; + } else { + printerr(1, "WARNING: unknown/unsupport mech OID\n"); ++ goto out_rel_buf; + } + + res = 0; +diff --git a/utils/gssd/gssd.c b/utils/gssd/gssd.c +index af66ed62..6f461fdf 100644 +--- a/utils/gssd/gssd.c ++++ b/utils/gssd/gssd.c +@@ -64,7 +64,7 @@ + #include + #include + #include +-#include ++#include + + #include "gssd.h" + #include "err_util.h" +@@ -77,7 +77,7 @@ static char *pipefs_path = GSSD_PIPEFS_DIR; + static DIR *pipefs_dir; + static int pipefs_fd; + static int inotify_fd; +-struct event inotify_ev; ++struct event *inotify_ev; + + char *keytabfile = GSSD_DEFAULT_KEYTAB_FILE; + char **ccachesearch; +@@ -90,9 +90,9 @@ char *ccachedir = NULL; + /* Avoid DNS reverse lookups on server names */ + static bool avoid_dns = true; + static bool use_gssproxy = false; +-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; ++static struct event_base *evbase = NULL; + + TAILQ_HEAD(topdir_list_head, topdir) topdir_list; + +@@ -359,20 +359,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 +388,30 @@ 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_ev) { ++ event_del(clp->krb5_ev); ++ event_free(clp->krb5_ev); ++ clp->krb5_ev = NULL; ++ } ++ ++ if (clp->gssd_ev) { ++ event_del(clp->gssd_ev); ++ event_free(clp->gssd_ev); ++ clp->gssd_ev = NULL; ++ } ++ ++ inotify_rm_watch(inotify_fd, clp->wd); ++ gssd_free_client(clp); ++} ++ + static void gssd_scan(void); + + static int +@@ -416,11 +448,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 +480,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 +503,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 +543,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; +@@ -535,15 +578,15 @@ gssd_scan_clnt(struct clnt_info *clp) + clp->krb5_fd = openat(clntfd, "krb5", O_RDWR | O_NONBLOCK); + + if (gssd_was_closed && clp->gssd_fd >= 0) { +- event_set(&clp->gssd_ev, clp->gssd_fd, EV_READ | EV_PERSIST, +- gssd_clnt_gssd_cb, clp); +- event_add(&clp->gssd_ev, NULL); ++ clp->gssd_ev = event_new(evbase, clp->gssd_fd, EV_READ | EV_PERSIST, ++ gssd_clnt_gssd_cb, clp); ++ event_add(clp->gssd_ev, NULL); + } + + if (krb5_was_closed && clp->krb5_fd >= 0) { +- event_set(&clp->krb5_ev, clp->krb5_fd, EV_READ | EV_PERSIST, +- gssd_clnt_krb5_cb, clp); +- event_add(&clp->krb5_ev, NULL); ++ clp->krb5_ev = event_new(evbase, clp->krb5_fd, EV_READ | EV_PERSIST, ++ gssd_clnt_krb5_cb, clp); ++ event_add(clp->krb5_ev, NULL); + } + + if (clp->krb5_fd == -1 && clp->gssd_fd == -1) +@@ -649,7 +692,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); +@@ -746,12 +789,16 @@ gssd_inotify_clnt(struct topdir *tdi, struct clnt_info *clp, const struct inotif + } else if (ev->mask & IN_DELETE) { + if (!strcmp(ev->name, "gssd") && clp->gssd_fd >= 0) { + close(clp->gssd_fd); +- event_del(&clp->gssd_ev); ++ event_del(clp->gssd_ev); ++ event_free(clp->gssd_ev); ++ clp->gssd_ev = NULL; + clp->gssd_fd = -1; + + } else if (!strcmp(ev->name, "krb5") && clp->krb5_fd >= 0) { + close(clp->krb5_fd); +- event_del(&clp->krb5_ev); ++ event_del(clp->krb5_ev); ++ event_free(clp->krb5_ev); ++ clp->krb5_ev = NULL; + clp->krb5_fd = -1; + } + +@@ -824,10 +871,15 @@ 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); ++ event_base_loopexit(evbase, NULL); + } + + static void +@@ -884,9 +936,10 @@ main(int argc, char *argv[]) + int rpc_verbosity = 0; + int opt; + int i; ++ int rc; + extern char *optarg; + char *progname; +- struct event sighup_ev; ++ struct event *sighup_ev; + + read_gss_conf(); + +@@ -1025,7 +1078,11 @@ main(int argc, char *argv[]) + if (gssd_check_mechs() != 0) + errx(1, "Problem with gssapi library"); + +- event_init(); ++ evbase = event_base_new(); ++ if (!evbase) { ++ printerr(0, "ERROR: failed to create event base\n"); ++ exit(EXIT_FAILURE); ++ } + + pipefs_dir = opendir(pipefs_path); + if (!pipefs_dir) { +@@ -1047,18 +1104,43 @@ main(int argc, char *argv[]) + + signal(SIGINT, sig_die); + signal(SIGTERM, sig_die); +- signal_set(&sighup_ev, SIGHUP, gssd_scan_cb, NULL); +- signal_add(&sighup_ev, NULL); +- event_set(&inotify_ev, inotify_fd, EV_READ | EV_PERSIST, gssd_inotify_cb, NULL); +- event_add(&inotify_ev, NULL); ++ sighup_ev = evsignal_new(evbase, SIGHUP, gssd_scan_cb, NULL); ++ evsignal_add(sighup_ev, NULL); ++ inotify_ev = event_new(evbase, inotify_fd, EV_READ | EV_PERSIST, ++ gssd_inotify_cb, NULL); ++ event_add(inotify_ev, NULL); + + TAILQ_INIT(&topdir_list); + gssd_scan(); + daemon_ready(); + +- event_dispatch(); ++ rc = event_base_dispatch(evbase); + +- 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_free(inotify_ev); ++ event_free(sighup_ev); ++ event_base_free(evbase); ++ ++ 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 f4f59754..1e8c58d4 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; +@@ -79,9 +76,9 @@ struct clnt_info { + int vers; + char *protocol; + int krb5_fd; +- struct event krb5_ev; ++ struct event *krb5_ev; + int gssd_fd; +- struct event gssd_ev; ++ struct event *gssd_ev; + struct sockaddr_storage addr; + }; + +@@ -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 bfcf3f09..ae3ebe81 100644 +--- a/utils/gssd/gssd_proc.c ++++ b/utils/gssd/gssd_proc.c +@@ -149,9 +149,10 @@ do_downcall(int k5_fd, uid_t uid, struct authgss_private_data *pd, + char *buf = NULL, *p = NULL, *end = NULL; + unsigned int timeout = context_timeout; + unsigned int buf_size = 0; ++ pthread_t tid = pthread_self(); + +- printerr(2, "doing downcall: lifetime_rec=%u acceptor=%.*s\n", +- lifetime_rec, acceptor->length, acceptor->value); ++ printerr(2, "do_downcall(0x%x): lifetime_rec=%u acceptor=%.*s\n", ++ tid, lifetime_rec, acceptor->length, acceptor->value); + buf_size = sizeof(uid) + sizeof(timeout) + sizeof(pd->pd_seq_win) + + sizeof(pd->pd_ctx_hndl.length) + pd->pd_ctx_hndl.length + + sizeof(context_token->length) + context_token->length + +@@ -177,7 +178,7 @@ do_downcall(int k5_fd, uid_t uid, struct authgss_private_data *pd, + return; + out_err: + free(buf); +- printerr(1, "Failed to write downcall!\n"); ++ printerr(1, "do_downcall(0x%x): Failed to write downcall!\n", tid); + return; + } + +@@ -231,7 +232,7 @@ populate_port(struct sockaddr *sa, const socklen_t salen, + switch (sa->sa_family) { + case AF_INET: + if (s4->sin_port != 0) { +- printerr(2, "DEBUG: port already set to %d\n", ++ printerr(4, "DEBUG: port already set to %d\n", + ntohs(s4->sin_port)); + return 1; + } +@@ -239,7 +240,7 @@ populate_port(struct sockaddr *sa, const socklen_t salen, + #ifdef IPV6_SUPPORTED + case AF_INET6: + if (s6->sin6_port != 0) { +- printerr(2, "DEBUG: port already set to %d\n", ++ printerr(4, "DEBUG: port already set to %d\n", + ntohs(s6->sin6_port)); + return 1; + } +@@ -544,7 +545,7 @@ krb5_use_machine_creds(struct clnt_info *clp, uid_t uid, + uid, tgtname); + + do { +- gssd_refresh_krb5_machine_credential(clp->servername, NULL, ++ gssd_refresh_krb5_machine_credential(clp->servername, + service, srchost); + /* + * Get a list of credential cache names and try each +@@ -726,7 +727,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, NULL); +- free(info); ++ free_upcall_info(info); + } + + void +@@ -743,8 +744,10 @@ handle_gssd_upcall(struct clnt_upcall_info *info) + char *enctypes = NULL; + char *upcall_str; + char *pbuf = info->lbuf; ++ pthread_t tid = pthread_self(); + +- printerr(2, "%s: '%s' (%s)\n", __func__, info->lbuf, clp->relpath); ++ printerr(2, "\n%s(0x%x): '%s' (%s)\n", __func__, tid, ++ info->lbuf, clp->relpath); + + upcall_str = strdup(info->lbuf); + if (upcall_str == NULL) { +@@ -826,6 +829,6 @@ 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 26e51edf..d675c3a4 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,18 @@ 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(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); ++} ++ + /* + * Called from the scandir function to weed out potential krb5 + * credentials cache files +@@ -352,12 +383,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 " +@@ -410,6 +444,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 +@@ -419,15 +454,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", +@@ -465,6 +503,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) +@@ -481,6 +520,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) +@@ -532,6 +572,7 @@ new_ple(krb5_context context, krb5_principal princ) + p->next = ple; + } + ++ ple->refcount = 1; + return ple; + outerr: + if (ple) { +@@ -550,13 +591,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; +@@ -721,6 +763,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; + } +@@ -796,12 +840,12 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, + /* Compute the active directory machine name HOST$ */ + krb5_appdefault_string(context, "nfs", NULL, "ad_principal_name", + notsetstr, &adhostoverride); +- if (strcmp(adhostoverride, notsetstr) != 0) { +- printerr (1, +- "AD host string overridden with \"%s\" from appdefaults\n", +- adhostoverride); +- /* No overflow: Windows cannot handle strings longer than 19 chars */ +- strcpy(myhostad, adhostoverride); ++ if (adhostoverride && strcmp(adhostoverride, notsetstr) != 0) { ++ printerr(1, ++ "AD host string overridden with \"%s\" from appdefaults\n", ++ adhostoverride); ++ /* No overflow: Windows cannot handle strings longer than 19 chars */ ++ strcpy(myhostad, adhostoverride); + } else { + strcpy(myhostad, myhostname); + for (i = 0; myhostad[i] != 0; ++i) { +@@ -928,7 +972,7 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, + tried_upper = 1; + } + } else { +- printerr(3, "Success getting keytab entry for '%s'\n",spn); ++ printerr(2, "Success getting keytab entry for '%s'\n",spn); + retval = 0; + goto out; + } +@@ -1053,6 +1097,93 @@ err_cache: + return (*ret_princname && *ret_realm); + } + ++/* ++ * 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, char *srchost) ++{ ++ 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 srchost=%s\n", ++ __func__, hostname, ple, service, srchost); ++ ++ /* ++ * 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, srchost, 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 ===*/ + /*==========================*/ +@@ -1146,37 +1277,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, 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, 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; + } +@@ -1201,7 +1351,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; +@@ -1213,33 +1363,38 @@ 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); +- krb5_free_string(context, 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); +- krb5_free_string(context, 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(context, ple); + } ++ pthread_mutex_unlock(&ple_lock); + krb5_free_context(context); +- out: +- krb5_free_string(context, k5err); + } + + /* +@@ -1247,83 +1402,10 @@ gssd_destroy_krb5_machine_creds(void) + */ + int + gssd_refresh_krb5_machine_credential(char *hostname, +- struct gssd_k5_kt_princ *ple, + char *service, char *srchost) + { +- 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 srchost=%s\n", +- __func__, hostname, ple, service, srchost); +- +- /* +- * 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, srchost, 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: +- krb5_free_string(context, k5err); +- return retval; ++ return gssd_refresh_krb5_machine_credential_internal(hostname, NULL, ++ service, srchost); + } + + /* +diff --git a/utils/gssd/krb5_util.h b/utils/gssd/krb5_util.h +index b000b444..2415205a 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 *srchost); + char *gssd_k5_err_msg(krb5_context context, krb5_error_code code); + void gssd_k5_get_default_realm(char **def_realm); diff --git a/SOURCES/nfs-utils-2.3.3-mountd-pseudofs.patch b/SOURCES/nfs-utils-2.3.3-mountd-pseudofs.patch new file mode 100644 index 0000000..04eb082 --- /dev/null +++ b/SOURCES/nfs-utils-2.3.3-mountd-pseudofs.patch @@ -0,0 +1,61 @@ +diff --git a/utils/mountd/v4root.c b/utils/mountd/v4root.c +index d735dbfe..8ec33fb0 100644 +--- a/utils/mountd/v4root.c ++++ b/utils/mountd/v4root.c +@@ -36,9 +36,9 @@ static nfs_export pseudo_root = { + .m_export = { + .e_hostname = "*", + .e_path = "/", +- .e_flags = NFSEXP_READONLY | NFSEXP_ROOTSQUASH ++ .e_flags = NFSEXP_READONLY + | NFSEXP_NOSUBTREECHECK | NFSEXP_FSID +- | NFSEXP_V4ROOT, ++ | NFSEXP_V4ROOT | NFSEXP_INSECURE_PORT, + .e_anonuid = 65534, + .e_anongid = 65534, + .e_squids = NULL, +@@ -57,15 +57,11 @@ static nfs_export pseudo_root = { + }; + + static void +-set_pseudofs_security(struct exportent *pseudo, int flags) ++set_pseudofs_security(struct exportent *pseudo) + { + struct flav_info *flav; + int i; + +- if (flags & NFSEXP_INSECURE_PORT) +- pseudo->e_flags |= NFSEXP_INSECURE_PORT; +- if ((flags & NFSEXP_ROOTSQUASH) == 0) +- pseudo->e_flags &= ~NFSEXP_ROOTSQUASH; + for (flav = flav_map; flav < flav_map + flav_map_size; flav++) { + struct sec_entry *new; + +@@ -75,8 +71,7 @@ set_pseudofs_security(struct exportent *pseudo, int flags) + i = secinfo_addflavor(flav, pseudo); + new = &pseudo->e_secinfo[i]; + +- if (flags & NFSEXP_INSECURE_PORT) +- new->flags |= NFSEXP_INSECURE_PORT; ++ new->flags |= NFSEXP_INSECURE_PORT; + } + } + +@@ -95,7 +90,7 @@ v4root_create(char *path, nfs_export *export) + strncpy(eep.e_path, path, sizeof(eep.e_path)-1); + if (strcmp(path, "/") != 0) + eep.e_flags &= ~NFSEXP_FSID; +- set_pseudofs_security(&eep, curexp->e_flags); ++ set_pseudofs_security(&eep); + exp = export_create(&eep, 0); + if (exp == NULL) + return NULL; +@@ -143,7 +138,7 @@ pseudofs_update(char *hostname, char *path, nfs_export *source) + return 0; + } + /* Update an existing V4ROOT export: */ +- set_pseudofs_security(&exp->m_export, source->m_export.e_flags); ++ set_pseudofs_security(&exp->m_export); + return 0; + } + diff --git a/SOURCES/nfs-utils-2.3.3-nfsdclddb-manpage-rename.patch b/SOURCES/nfs-utils-2.3.3-nfsdclddb-manpage-rename.patch new file mode 100644 index 0000000..8d7991a --- /dev/null +++ b/SOURCES/nfs-utils-2.3.3-nfsdclddb-manpage-rename.patch @@ -0,0 +1,29 @@ +commit 3e81185037cf97990e4598218f56d92dd70d6269 +Author: NeilBrown +Date: Tue Oct 20 13:19:10 2020 -0400 + + clddb-tool was recently renamed to nfsdclddb. + Unfortunately the nfsdcld man page wasn't told. + + Signed-off-by: NeilBrown + Signed-off-by: Steve Dickson + +diff --git a/utils/nfsdcld/nfsdcld.man b/utils/nfsdcld/nfsdcld.man +index 4c2b1e80..861f1c49 100644 +--- a/utils/nfsdcld/nfsdcld.man ++++ b/utils/nfsdcld/nfsdcld.man +@@ -209,12 +209,12 @@ not necessary after upgrading \fBnfsdcld\fR, however \fBnfsd\fR will not use a l + version until restart. A restart of \fBnfsd is necessary\fR after downgrading \fBnfsdcld\fR, + to ensure that \fBnfsd\fR does not use an upcall version that \fBnfsdcld\fR does not support. + Additionally, a downgrade of \fBnfsdcld\fR requires the schema of the on-disk database to +-be downgraded as well. That can be accomplished using the \fBclddb-tool\fR(8) utility. ++be downgraded as well. That can be accomplished using the \fBnfsdclddb\fR(8) utility. + .SH FILES + .TP + .B /var/lib/nfs/nfsdcld/main.sqlite + .SH SEE ALSO +-.BR nfsdcltrack "(8), " clddb-tool (8) ++.BR nfsdcltrack "(8), " nfsdclddb (8) + .SH "AUTHORS" + .IX Header "AUTHORS" + The nfsdcld daemon was developed by Jeff Layton diff --git a/SOURCES/nfs-utils-2.3.3-nfsiostat-div-zero.patch b/SOURCES/nfs-utils-2.3.3-nfsiostat-div-zero.patch new file mode 100644 index 0000000..8e6d1b3 --- /dev/null +++ b/SOURCES/nfs-utils-2.3.3-nfsiostat-div-zero.patch @@ -0,0 +1,12 @@ +diff -up nfs-utils-2.3.3/tools/nfs-iostat/nfs-iostat.py.orig nfs-utils-2.3.3/tools/nfs-iostat/nfs-iostat.py +--- nfs-utils-2.3.3/tools/nfs-iostat/nfs-iostat.py.orig 2020-12-10 10:38:26.462195326 -0500 ++++ nfs-utils-2.3.3/tools/nfs-iostat/nfs-iostat.py 2020-12-10 10:45:47.210671473 -0500 +@@ -380,6 +380,8 @@ class DeviceData: + sends = float(self.__rpc_data['rpcsends']) + if sample_time == 0: + sample_time = float(self.__nfs_data['age']) ++ if sample_time == 0: ++ sample_time = 1; + return (sends / sample_time) + + def display_iostats(self, sample_time, which): diff --git a/SOURCES/nfs-utils-2.3.3-nfsiostat-key-error.patch b/SOURCES/nfs-utils-2.3.3-nfsiostat-key-error.patch new file mode 100644 index 0000000..e628c09 --- /dev/null +++ b/SOURCES/nfs-utils-2.3.3-nfsiostat-key-error.patch @@ -0,0 +1,37 @@ +diff -up nfs-utils-2.3.3/tools/mountstats/mountstats.py.orig nfs-utils-2.3.3/tools/mountstats/mountstats.py +--- nfs-utils-2.3.3/tools/mountstats/mountstats.py.orig 2020-12-10 10:48:17.319579958 -0500 ++++ nfs-utils-2.3.3/tools/mountstats/mountstats.py 2020-12-10 10:52:42.481484160 -0500 +@@ -943,10 +943,11 @@ def print_iostat_summary(old, new, devic + if not old or device not in old: + stats.display_iostats(time) + else: +- old_stats = DeviceData() +- old_stats.parse_stats(old[device]) +- diff_stats = stats.compare_iostats(old_stats) +- diff_stats.display_iostats(time) ++ if ("fstype autofs" not in str(old[device])) and ("fstype autofs" not in str(new[device])): ++ old_stats = DeviceData() ++ old_stats.parse_stats(old[device]) ++ diff_stats = stats.compare_iostats(old_stats) ++ diff_stats.display_iostats(time) + + def iostat_command(args): + """iostat-like command for NFS mount points +diff -up nfs-utils-2.3.3/tools/nfs-iostat/nfs-iostat.py.orig nfs-utils-2.3.3/tools/nfs-iostat/nfs-iostat.py +--- nfs-utils-2.3.3/tools/nfs-iostat/nfs-iostat.py.orig 2020-12-10 10:48:17.316579880 -0500 ++++ nfs-utils-2.3.3/tools/nfs-iostat/nfs-iostat.py 2020-12-10 10:52:42.481484160 -0500 +@@ -467,10 +467,13 @@ def parse_stats_file(filename): + def print_iostat_summary(old, new, devices, time, options): + stats = {} + diff_stats = {} ++ devicelist = [] + if old: + # Trim device list to only include intersection of old and new data, + # this addresses umounts due to autofs mountpoints +- devicelist = [x for x in old if x in devices] ++ for device in devices: ++ if "fstype autofs" not in str(old[device]): ++ devicelist.append(device) + else: + devicelist = devices + diff --git a/SOURCES/nfs-utils-2.3.3-systemd-exportfs-nofail.patch b/SOURCES/nfs-utils-2.3.3-systemd-exportfs-nofail.patch new file mode 100644 index 0000000..a41bdd7 --- /dev/null +++ b/SOURCES/nfs-utils-2.3.3-systemd-exportfs-nofail.patch @@ -0,0 +1,37 @@ +commit 003000d451833309c963054e58a48fa1df7e767b +Author: Steve Dickson +Date: Thu Dec 10 13:13:03 2020 -0500 + + exportfs: Ingnore export failures in nfs-server.serivce unit + + With some recent commits, exportfs will continue on trying to + export filesystems even when an entry is invalid or does + not exist, but will still have a non-zero exit to report + the error. + + This situation should not stop the nfs-server service + from comingup so nfs-server.service file should + ignore these types of failures + + Signed-off-by: Steve Dickson + +diff --git a/systemd/nfs-server.service b/systemd/nfs-server.service +index 06c1adb7..b432f910 100644 +--- a/systemd/nfs-server.service ++++ b/systemd/nfs-server.service +@@ -21,13 +21,13 @@ After=rpc-gssd.service gssproxy.service rpc-svcgssd.service + [Service] + Type=oneshot + RemainAfterExit=yes +-ExecStartPre=/usr/sbin/exportfs -r ++ExecStartPre=-/usr/sbin/exportfs -r + ExecStart=/usr/sbin/rpc.nfsd + ExecStop=/usr/sbin/rpc.nfsd 0 + ExecStopPost=/usr/sbin/exportfs -au + ExecStopPost=/usr/sbin/exportfs -f + +-ExecReload=/usr/sbin/exportfs -r ++ExecReload=-/usr/sbin/exportfs -r + + [Install] + WantedBy=multi-user.target diff --git a/SPECS/nfs-utils.spec b/SPECS/nfs-utils.spec index 04d3e5d..2d9af3b 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://linux-nfs.org/ Version: 2.3.3 -Release: 35%{?dist} +Release: 41%{?dist} Epoch: 1 # group all 32bit related archs @@ -61,6 +61,18 @@ Patch027: nfs-utils-2.3.3-nconnect-manpage.patch Patch028: nfs-utils-2.3.3-nfsdclddb-rename.patch Patch029: nfs-utils-2.3.3-nfsclnts-cmd.patch +# +# RHEL 8.4 +# +Patch030: nfs-utils-2.3.3-exportfs-man-labels.patch +Patch031: nfs-utils-2.3.3-nfsiostat-div-zero.patch +Patch032: nfs-utils-2.3.3-nfsiostat-key-error.patch +Patch033: nfs-utils-2.3.3-nfsdclddb-manpage-rename.patch +Patch034: nfs-utils-2.3.3-systemd-exportfs-nofail.patch +Patch035: nfs-utils-2.3.3-exports-manpage-outdated.patch +Patch036: nfs-utils-2.3.3-gssd-multithread-updates.patch +Patch037: nfs-utils-2.3.3-mountd-pseudofs.patch + Patch100: nfs-utils-1.2.1-statdpath-man.patch Patch101: nfs-utils-1.2.1-exp-subtree-warn-off.patch Patch102: nfs-utils-2.3.3-idmap-errmsg.patch @@ -223,8 +235,6 @@ done cat /etc/group | cut -d':' -f 1 | grep --quiet rpcuser 2>/dev/null if [ "$?" -eq 1 ]; then /usr/sbin/groupadd -g %{rpcuser_uid} rpcuser >/dev/null 2>&1 || : -else - /usr/sbin/groupmod -g %{rpcuser_uid} rpcuser >/dev/null 2>&1 || : fi # Create rpcuser uid as long as it does not already exist. @@ -253,11 +263,6 @@ if [ $? -eq 1 ]; then fi %post - -# Enable nfs-convert so if an old configuration -# exists a conversion will occur -/bin/systemctl enable nfs-convert >/dev/null 2>&1 || : - if [ $1 -eq 1 ] ; then # Initial installation /bin/systemctl enable nfs-client.target >/dev/null 2>&1 || : @@ -270,8 +275,6 @@ if [ $1 -eq 0 ]; then %systemd_preun nfs-client.target %systemd_preun nfs-server.server - rm -rf /var/lib/nfs/statd - rm -rf /var/lib/nfs/v4recovery fi %postun @@ -280,6 +283,11 @@ fi /bin/systemctl --system daemon-reload >/dev/null 2>&1 || : +if [ $1 -eq 0 ] ; then + rm -rf /var/lib/nfs/statd + rm -rf /var/lib/nfs/v4recovery +fi + %triggerin -- nfs-utils > 1:2.1.1-3 /bin/systemctl try-restart gssproxy || : @@ -347,6 +355,29 @@ fi %{_libdir}/libnfsidmap.so %changelog +* Wed Jan 20 2021 Steve Dickson 2.3.3-41 +- mountd: never root squash on the pseudofs (bz 1804912) + +* Mon Dec 14 2020 Steve Dickson 2.3.3-40 +- gssd: upstream multithreaded updates (bz 1906792) + +* Fri Dec 11 2020 Steve Dickson 2.3.3-39 +- systemd: Ingnore export failures in nfs-server.serivce unit (bz 1894873) +- exports.man: Remove some outdated verbiage (bz 1769688) + +* Thu Dec 10 2020 Steve Dickson 2.3.3-38 +- exports man page: warn about subdirectory exports (bz 1652437) +- Don't modify /etc/group on upgrades (bz 1856881) +- nfs-iostat: divide by zero with fresh mount (bz 1861823) +- nfsiostat: Drop autofs entries before calling compare_iostats() (bz 1859130) +- nfsdclddb: clddb-tool was recently renamed to nfsdclddb (bz 1893599) + +* Thu Dec 10 2020 Alice Mitchell 2.3.3-37 +- Remove manual enabling of nfs-convert (bz 1683895) + +* Fri Oct 9 2020 Alice Mitchell 2.3.3-36 +- Fix uninstall warnings (bz 1733170) + * Wed Jun 10 2020 Steve Dickson 2.3.3-35 - Fix dependency problems with nfsdclnts (bz 1841502)