diff --git a/nfs-utils-1.2.6-rc5.patch b/nfs-utils-1.2.6-rc5.patch deleted file mode 100644 index 592b36d..0000000 --- a/nfs-utils-1.2.6-rc5.patch +++ /dev/null @@ -1,1115 +0,0 @@ -diff --git a/aclocal/ipv6.m4 b/aclocal/ipv6.m4 -index 5ee8fb6..4e39fbe 100644 ---- a/aclocal/ipv6.m4 -+++ b/aclocal/ipv6.m4 -@@ -2,11 +2,6 @@ dnl Checks for IPv6 support - dnl - AC_DEFUN([AC_IPV6], [ - -- AC_CHECK_DECL([AI_ADDRCONFIG], -- [AC_DEFINE([HAVE_DECL_AI_ADDRCONFIG], 1, -- [Define this to 1 if AI_ADDRCONFIG macro is defined])], , -- [ #include ]) -- - if test "$enable_ipv6" = yes; then - - dnl TI-RPC required for IPv6 -@@ -18,12 +13,6 @@ AC_DEFUN([AC_IPV6], [ - AC_CHECK_FUNCS([getifaddrs getnameinfo bindresvport_sa], , - [AC_MSG_ERROR([Missing library functions needed for IPv6.])]) - -- dnl Need to detect presence of IPv6 networking at run time via -- dnl getaddrinfo(3); old versions of glibc do not support ADDRCONFIG -- AC_CHECK_DECL([AI_ADDRCONFIG], , -- [AC_MSG_ERROR([full getaddrinfo(3) implementation needed for IPv6 support])], -- [ #include ]) -- - fi - - ])dnl -diff --git a/aclocal/libevent.m4 b/aclocal/libevent.m4 -index 3c962b3..b5ac00f 100644 ---- a/aclocal/libevent.m4 -+++ b/aclocal/libevent.m4 -@@ -2,8 +2,9 @@ dnl Checks for libevent - AC_DEFUN([AC_LIBEVENT], [ - - dnl Check for libevent, but do not add -levent to LIBS -- AC_CHECK_LIB([event], [event_dispatch], [libevent=1], -+ AC_CHECK_LIB([event], [event_dispatch], [LIBEVENT=-levent], - [AC_MSG_ERROR([libevent not found.])]) -+ AC_SUBST(LIBEVENT) - - AC_CHECK_HEADERS([event.h], , - [AC_MSG_ERROR([libevent headers not found.])]) -diff --git a/aclocal/libnfsidmap.m4 b/aclocal/libnfsidmap.m4 -index 484b1ec..ae697e8 100644 ---- a/aclocal/libnfsidmap.m4 -+++ b/aclocal/libnfsidmap.m4 -@@ -3,7 +3,7 @@ dnl - AC_DEFUN([AC_LIBNFSIDMAP], [ - - dnl Check for libnfsidmap, but do not add -lnfsidmap to LIBS -- AC_CHECK_LIB([nfsidmap], [nfs4_init_name_mapping], [libnfsidmap=1], -+ AC_CHECK_LIB([nfsidmap], [nfs4_init_name_mapping], [LIBNFSIDMAP=-lnfsidmap], - [AC_MSG_ERROR([libnfsidmap not found.])]) - - AC_CHECK_HEADERS([nfsidmap.h], , -@@ -14,7 +14,10 @@ AC_DEFUN([AC_LIBNFSIDMAP], [ - [AC_DEFINE([HAVE_NFS4_SET_DEBUG], 1, - [Define to 1 if you have the `nfs4_set_debug' function.])]) - -- dnl only enable nfsidmap when libnfsidmap supports it -- AC_CHECK_LIB([nfsidmap], [nfs4_owner_to_uid]) -+ dnl nfs4_owner_to_uid() doesn't appear in all versions of libnfsidmap -+ dnl We just need this test to set $ac_cv_lib_nfsidmap_nfs4_owner_to_uid -+ AC_CHECK_LIB([nfsidmap], [nfs4_owner_to_uid], [:]) -+ -+ AC_SUBST(LIBNFSIDMAP) - - ])dnl -diff --git a/configure.ac b/configure.ac -index 80fb39d..920e8da 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -24,9 +24,8 @@ AC_ARG_WITH(statedir, - statedir=/var/lib/nfs) - AC_SUBST(statedir) - AC_ARG_WITH(statdpath, -- [AC_HELP_STRING([--with-statdpath=/foo @<:@default=/var/lib/nfs@:>@], -- [define statd's state dir as /foo instead of the NFS statedir] -- )], -+ [AC_HELP_STRING([--with-statdpath=/foo], -+ [define the statd state dir as /foo instead of the NFS statedir @<:@default=/var/lib/nfs@:>@])], - statdpath=$withval, - statdpath=$statedir - ) -@@ -249,6 +248,8 @@ AC_CHECK_FUNC([getservbyname], , - - AC_CHECK_LIB([crypt], [crypt], [LIBCRYPT="-lcrypt"]) - -+AC_CHECK_LIB([dl], [dlclose], [LIBDL="-ldl"]) -+ - if test "$enable_nfsv4" = yes; then - dnl check for libevent libraries and headers - AC_LIBEVENT -@@ -265,6 +266,12 @@ if test "$enable_nfsv4" = yes; then - AC_RPCSEC_VERSION - fi - fi -+ -+if test "$enable_nfsv41" = yes; then -+ AC_CHECK_LIB([devmapper], [dm_task_create], [LIBDEVMAPPER="-ldevmapper"], AC_MSG_ERROR([libdevmapper needed])) -+ AC_CHECK_HEADER(libdevmapper.h, , AC_MSG_ERROR([Cannot find devmapper header file libdevmapper.h])) -+fi -+ - dnl enable nfsidmap when its support by libnfsidmap - AM_CONDITIONAL(CONFIG_NFSIDMAP, [test "$ac_cv_header_keyutils_h$ac_cv_lib_nfsidmap_nfs4_owner_to_uid" = "yesyes"]) - -@@ -293,6 +300,7 @@ AC_SUBST(LIBSOCKET) - AC_SUBST(LIBCRYPT) - AC_SUBST(LIBBSD) - AC_SUBST(LIBBLKID) -+AC_SUBST(LIBDL) - - if test "$enable_libmount" != no; then - AC_CHECK_LIB(mount, mnt_context_do_mount, [LIBMOUNT="-lmount"], AC_MSG_ERROR([libmount needed])) -@@ -330,7 +338,7 @@ AC_CHECK_HEADERS([arpa/inet.h fcntl.h libintl.h limits.h \ - stdlib.h string.h sys/file.h sys/ioctl.h sys/mount.h \ - sys/param.h sys/socket.h sys/time.h sys/vfs.h \ - syslog.h unistd.h com_err.h et/com_err.h \ -- ifaddrs.h]) -+ ifaddrs.h nfs-plugin.h]) - - dnl ************************************************************* - dnl Checks for typedefs, structures, and compiler characteristics -diff --git a/support/include/nfs/debug.h b/support/include/nfs/debug.h -index d391e91..dbec5ba 100644 ---- a/support/include/nfs/debug.h -+++ b/support/include/nfs/debug.h -@@ -76,6 +76,9 @@ enum { - #define NFSDBG_CALLBACK 0x0100 - #define NFSDBG_CLIENT 0x0200 - #define NFSDBG_MOUNT 0x0400 -+#define NFSDBG_FSCACHE 0x0800 -+#define NFSDBG_PNFS 0x1000 -+#define NFSDBG_PNFS_LD 0x2000 - #define NFSDBG_ALL 0xFFFF - - #endif /* _NFS_DEBUG_H */ -diff --git a/support/nfs/conffile.c b/support/nfs/conffile.c -index fa0dc6b..3990578 100644 ---- a/support/nfs/conffile.c -+++ b/support/nfs/conffile.c -@@ -256,13 +256,14 @@ conf_parse_line(int trans, char *line, size_t sz) - val++, j++; - if (*val) - i = j; -- section = malloc(i); -+ section = malloc(i+1); - if (!section) { - xlog_warn("conf_parse_line: %d: malloc (%lu) failed", ln, - (unsigned long)i); - return; - } - strncpy(section, line, i); -+ section[i] = '\0'; - - if (arg) - free(arg); -diff --git a/support/nfs/nfsctl.c b/support/nfs/nfsctl.c -index 89fa1a4..fec775f 100644 ---- a/support/nfs/nfsctl.c -+++ b/support/nfs/nfsctl.c -@@ -11,16 +11,22 @@ - #endif - - #include -+#include - #include - #include "nfslib.h" - - /* compatibility hack... */ --#ifndef __NR_nfsctl -+#if !defined(__NR_nfsctl) && defined(__NR_nfsservctl) - #define __NR_nfsctl __NR_nfsservctl - #endif - - int - nfsctl (int cmd, struct nfsctl_arg * argp, union nfsctl_res * resp) - { -+#ifdef __NR_nfsctl - return syscall (__NR_nfsctl, cmd, argp, resp); -+#else -+ errno = ENOSYS; -+ return -1; -+#endif - } -diff --git a/tools/rpcdebug/rpcdebug.c b/tools/rpcdebug/rpcdebug.c -index 275a491..444616d 100644 ---- a/tools/rpcdebug/rpcdebug.c -+++ b/tools/rpcdebug/rpcdebug.c -@@ -167,6 +167,9 @@ static struct flagmap { - FLAG(NFS, CALLBACK), - FLAG(NFS, CLIENT), - FLAG(NFS, MOUNT), -+ FLAG(NFS, FSCACHE), -+ FLAG(NFS, PNFS), -+ FLAG(NFS, PNFS_LD), - FLAG(NFS, ALL), - - /* nfsd */ -diff --git a/utils/blkmapd/device-process.c b/utils/blkmapd/device-process.c -index 27ff374..652a7a8 100644 ---- a/utils/blkmapd/device-process.c -+++ b/utils/blkmapd/device-process.c -@@ -296,7 +296,7 @@ decode_blk_volume(uint32_t **pp, uint32_t *end, struct bl_volume *vols, int voln - off_t stripe_unit = vol->param.bv_stripe_unit; - /* Check limitations imposed by device-mapper */ - if ((stripe_unit & (stripe_unit - 1)) != 0 -- || stripe_unit < (off_t) (PAGE_SIZE >> 9)) -+ || stripe_unit < (off_t) (sysconf(_SC_PAGE_SIZE) >> 9)) - return -EIO; - BLK_READBUF(p, end, 4); - READ32(vol->bv_vol_n); -diff --git a/utils/exportfs/exportfs.man b/utils/exportfs/exportfs.man -index 364f247..8853486 100644 ---- a/utils/exportfs/exportfs.man -+++ b/utils/exportfs/exportfs.man -@@ -177,7 +177,7 @@ In this way - .B exportfs - can be used to modify the export options of an already exported directory. - .SS Unexporting Directories --The third synopsis shows how to unexported a currently exported directory. -+The third synopsis shows how to unexport a currently exported directory. - When using - .BR "exportfs -ua" , - all entries listed in -diff --git a/utils/exportfs/nfsd.man b/utils/exportfs/nfsd.man -index 7365a1b..47b73be 100644 ---- a/utils/exportfs/nfsd.man -+++ b/utils/exportfs/nfsd.man -@@ -12,7 +12,7 @@ nfsd \- special filesystem for controlling Linux NFS server - .SH DESCRIPTION - The - .B nfsd --filesytem is a special filesystem which provides access to the Linux -+filesystem is a special filesystem which provides access to the Linux - NFS server. The filesystem consists of a single directory which - contains a number of files. These files are actually gateways into - the NFS server. Writing to them can affect the server. Reading from -@@ -86,7 +86,7 @@ should be followed by a newline, with white-space separating the - fields, and octal quoting of special characters. - - On writing this, the program will be able to read back a filehandle --for that path as exported to the given client. The filehandles length -+for that path as exported to the given client. The filehandle's length - will be at most the number of bytes given. - - The filehandle will be represented in hex with a leading '\ex'. -@@ -165,7 +165,7 @@ file. The user-space program might then write - .ti +5 - nfsd 127.0.0.1 1057206953 localhost - .br --to indicate that 127.0.0.1 should map to localhost, atleast for now. -+to indicate that 127.0.0.1 should map to localhost, at least for now. - - If the program uses select(2) or poll(2) to discover if it can read - from the -diff --git a/utils/gssd/Makefile.am b/utils/gssd/Makefile.am -index d7888ad..9136189 100644 ---- a/utils/gssd/Makefile.am -+++ b/utils/gssd/Makefile.am -@@ -58,7 +58,7 @@ svcgssd_SOURCES = \ - - svcgssd_LDADD = \ - ../../support/nfs/libnfs.a \ -- $(RPCSECGSS_LIBS) $(GSSGLUE_LIBS) -lnfsidmap \ -+ $(RPCSECGSS_LIBS) $(GSSGLUE_LIBS) $(LIBNFSIDMAP) \ - $(KRBLIBS) - - svcgssd_LDFLAGS = $(KRBLDFLAGS) -diff --git a/utils/gssd/context_lucid.c b/utils/gssd/context_lucid.c -index 3e695ab..64146d7 100644 ---- a/utils/gssd/context_lucid.c -+++ b/utils/gssd/context_lucid.c -@@ -80,6 +80,7 @@ prepare_krb5_rfc1964_buffer(gss_krb5_lucid_context_v1_t *lctx, - uint32_t i; - char *skd, *dkd; - gss_buffer_desc fakeoid; -+ int err; - - /* - * The new Kerberos interface to get the gss context -@@ -138,11 +139,10 @@ prepare_krb5_rfc1964_buffer(gss_krb5_lucid_context_v1_t *lctx, - dkd = (char *) enc_key.data; - for (i = 0; i < enc_key.length; i++) - dkd[i] = skd[i] ^ 0xf0; -- if (write_lucid_keyblock(&p, end, &enc_key)) { -- free(enc_key.data); -- goto out_err; -- } -+ err = write_lucid_keyblock(&p, end, &enc_key); - free(enc_key.data); -+ if (err) -+ goto out_err; - - if (write_lucid_keyblock(&p, end, &lctx->rfc1964_kd.ctx_key)) - goto out_err; -@@ -153,7 +153,6 @@ out_err: - printerr(0, "ERROR: failed serializing krb5 context for kernel\n"); - if (buf->value) free(buf->value); - buf->length = 0; -- if (enc_key.data) free(enc_key.data); - return -1; - } - -diff --git a/utils/idmapd/Makefile.am b/utils/idmapd/Makefile.am -index 4328e41..58b33ec 100644 ---- a/utils/idmapd/Makefile.am -+++ b/utils/idmapd/Makefile.am -@@ -16,7 +16,7 @@ idmapd_SOURCES = \ - nfs_idmap.h \ - queue.h - --idmapd_LDADD = -levent -lnfsidmap ../../support/nfs/libnfs.a -+idmapd_LDADD = $(LIBEVENT) $(LIBNFSIDMAP) ../../support/nfs/libnfs.a - - MAINTAINERCLEANFILES = Makefile.in - -diff --git a/utils/idmapd/idmapd.c b/utils/idmapd/idmapd.c -index 19d9114..e80efb4 100644 ---- a/utils/idmapd/idmapd.c -+++ b/utils/idmapd/idmapd.c -@@ -778,8 +778,8 @@ nfsopen(struct idmap_client *ic) - } else { - event_set(&ic->ic_event, ic->ic_fd, EV_READ, nfscb, ic); - event_add(&ic->ic_event, NULL); -- fcntl(ic->ic_dirfd, F_SETSIG, 0); - fcntl(ic->ic_dirfd, F_NOTIFY, 0); -+ fcntl(ic->ic_dirfd, F_SETSIG, 0); - if (verbose > 0) - xlog_warn("Opened %s", ic->ic_path); - } -diff --git a/utils/mount/mount_libmount.c b/utils/mount/mount_libmount.c -index e450d79..e8f17a9 100644 ---- a/utils/mount/mount_libmount.c -+++ b/utils/mount/mount_libmount.c -@@ -346,6 +346,21 @@ static int mount_main(struct libmnt_context *cxt, int argc, char **argv) - - if (chk_mountpoint(mount_point)) - goto err; -+ -+ /* -+ * The libmount strictly uses only options from fstab if running in -+ * restricted mode (suid, non-root user). This is done in -+ * mnt_context_prepare_mount() by default. -+ * -+ * We have to read fstab before nfsmount.conf, otherwise the options -+ * from nfsmount.conf will be ignored (overwrited). -+ */ -+ rc = mnt_context_apply_fstab(cxt); -+ if (rc) { -+ nfs_error(_("%s: failed to apply fstab options\n"), progname); -+ goto err; -+ } -+ - /* - * Concatenate mount options from the configuration file - */ -diff --git a/utils/mount/nfs.man b/utils/mount/nfs.man -index ce40933..2ad92d1 100644 ---- a/utils/mount/nfs.man -+++ b/utils/mount/nfs.man -@@ -1561,10 +1561,10 @@ To ensure that the saved mount options are not erased during a remount, - specify either the local mount directory, or the server hostname and - export pathname, but not both, during a remount. For example, - .P --.NF --.TA 2.5i -+.nf -+.ta 8n - mount -o remount,ro /mnt --.FI -+.fi - .P - merges the mount option - .B ro -diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c -index 314a806..d52e21a 100644 ---- a/utils/mount/stropts.c -+++ b/utils/mount/stropts.c -@@ -540,6 +540,8 @@ nfs_rewrite_pmap_mount_options(struct mount_options *options) - errno = EOPNOTSUPP; - else if (rpc_createerr.cf_stat == RPC_AUTHERROR) - errno = EACCES; -+ else if (rpc_createerr.cf_stat == RPC_TIMEDOUT) -+ errno = ETIMEDOUT; - else if (rpc_createerr.cf_error.re_errno != 0) - errno = rpc_createerr.cf_error.re_errno; - return 0; -@@ -665,9 +667,10 @@ static int nfs_try_mount_v3v2(struct nfsmount_info *mi) - case EHOSTUNREACH: - continue; - default: -- break; -+ goto out; - } - } -+out: - return ret; - } - -@@ -751,9 +754,10 @@ static int nfs_try_mount_v4(struct nfsmount_info *mi) - case EHOSTUNREACH: - continue; - default: -- break; -+ goto out; - } - } -+out: - return ret; - } - -diff --git a/utils/mountd/Makefile.am b/utils/mountd/Makefile.am -index eba81fc..5a2d1b6 100644 ---- a/utils/mountd/Makefile.am -+++ b/utils/mountd/Makefile.am -@@ -12,7 +12,7 @@ mountd_SOURCES = mountd.c mount_dispatch.c auth.c rmtab.c cache.c \ - mountd_LDADD = ../../support/export/libexport.a \ - ../../support/nfs/libnfs.a \ - ../../support/misc/libmisc.a \ -- $(LIBBSD) $(LIBWRAP) $(LIBNSL) $(LIBBLKID) -+ $(LIBBSD) $(LIBWRAP) $(LIBNSL) $(LIBBLKID) $(LIBDL) - mountd_CPPFLAGS = $(AM_CPPFLAGS) $(CPPFLAGS) \ - -I$(top_builddir)/support/include \ - -I$(top_srcdir)/support/export -diff --git a/utils/mountd/cache.c b/utils/mountd/cache.c -index d2ae456..ac9cdbd 100644 ---- a/utils/mountd/cache.c -+++ b/utils/mountd/cache.c -@@ -802,6 +802,229 @@ lookup_export(char *dom, char *path, struct addrinfo *ai) - return found; - } - -+#ifdef HAVE_NFS_PLUGIN_H -+#include -+#include -+ -+/* -+ * Walk through a set of FS locations and build a set of export options. -+ * Returns true if all went to plan; otherwise, false. -+ */ -+static _Bool -+locations_to_options(struct jp_ops *ops, nfs_fsloc_set_t locations, -+ char *options, size_t remaining, int *ttl) -+{ -+ char *server, *last_path, *rootpath, *ptr; -+ _Bool seen = false; -+ -+ last_path = NULL; -+ rootpath = NULL; -+ server = NULL; -+ ptr = options; -+ *ttl = 0; -+ -+ for (;;) { -+ enum jp_status status; -+ int len; -+ -+ status = ops->jp_get_next_location(locations, &server, -+ &rootpath, ttl); -+ if (status == JP_EMPTY) -+ break; -+ if (status != JP_OK) { -+ xlog(D_GENERAL, "%s: failed to parse location: %s", -+ __func__, ops->jp_error(status)); -+ goto out_false; -+ } -+ xlog(D_GENERAL, "%s: Location: %s:%s", -+ __func__, server, rootpath); -+ -+ if (last_path && strcmp(rootpath, last_path) == 0) { -+ len = snprintf(ptr, remaining, "+%s", server); -+ if (len < 0) { -+ xlog(D_GENERAL, "%s: snprintf: %m", __func__); -+ goto out_false; -+ } -+ if ((size_t)len >= remaining) { -+ xlog(D_GENERAL, "%s: options buffer overflow", __func__); -+ goto out_false; -+ } -+ remaining -= (size_t)len; -+ ptr += len; -+ } else { -+ if (last_path == NULL) -+ len = snprintf(ptr, remaining, "refer=%s@%s", -+ rootpath, server); -+ else -+ len = snprintf(ptr, remaining, ":%s@%s", -+ rootpath, server); -+ if (len < 0) { -+ xlog(D_GENERAL, "%s: snprintf: %m", __func__); -+ goto out_false; -+ } -+ if ((size_t)len >= remaining) { -+ xlog(D_GENERAL, "%s: options buffer overflow", -+ __func__); -+ goto out_false; -+ } -+ remaining -= (size_t)len; -+ ptr += len; -+ last_path = rootpath; -+ } -+ -+ seen = true; -+ free(rootpath); -+ free(server); -+ } -+ -+ xlog(D_CALL, "%s: options='%s', ttl=%d", -+ __func__, options, *ttl); -+ return seen; -+ -+out_false: -+ free(rootpath); -+ free(server); -+ return false; -+} -+ -+/* -+ * Walk through the set of FS locations and build an exportent. -+ * Returns pointer to an exportent if "junction" refers to a junction. -+ * -+ * Returned exportent points to static memory. -+ */ -+static struct exportent *do_locations_to_export(struct jp_ops *ops, -+ nfs_fsloc_set_t locations, const char *junction, -+ char *options, size_t options_len) -+{ -+ struct exportent *exp; -+ int ttl; -+ -+ if (!locations_to_options(ops, locations, options, options_len, &ttl)) -+ return NULL; -+ -+ exp = mkexportent("*", (char *)junction, options); -+ if (exp == NULL) { -+ xlog(L_ERROR, "%s: Failed to construct exportent", __func__); -+ return NULL; -+ } -+ -+ exp->e_uuid = NULL; -+ exp->e_ttl = ttl; -+ return exp; -+} -+ -+/* -+ * Convert set of FS locations to an exportent. Returns pointer to -+ * an exportent if "junction" refers to a junction. -+ * -+ * Returned exportent points to static memory. -+ */ -+static struct exportent *locations_to_export(struct jp_ops *ops, -+ nfs_fsloc_set_t locations, const char *junction) -+{ -+ struct exportent *exp; -+ char *options; -+ -+ options = malloc(BUFSIZ); -+ if (options == NULL) { -+ xlog(D_GENERAL, "%s: failed to allocate options buffer", -+ __func__); -+ return NULL; -+ } -+ options[0] = '\0'; -+ -+ exp = do_locations_to_export(ops, locations, junction, -+ options, BUFSIZ); -+ -+ free(options); -+ return exp; -+} -+ -+/* -+ * Retrieve locations information in "junction" and dump it to the -+ * kernel. Returns pointer to an exportent if "junction" refers -+ * to a junction. -+ * -+ * Returned exportent points to static memory. -+ */ -+static struct exportent *invoke_junction_ops(void *handle, -+ const char *junction) -+{ -+ nfs_fsloc_set_t locations; -+ struct exportent *exp; -+ enum jp_status status; -+ struct jp_ops *ops; -+ char *error; -+ -+ ops = (struct jp_ops *)dlsym(handle, "nfs_junction_ops"); -+ error = dlerror(); -+ if (error != NULL) { -+ xlog(D_GENERAL, "%s: dlsym(jp_junction_ops): %s", -+ __func__, error); -+ return NULL; -+ } -+ if (ops->jp_api_version != JP_API_VERSION) { -+ xlog(D_GENERAL, "%s: unrecognized junction API version: %u", -+ __func__, ops->jp_api_version); -+ return NULL; -+ } -+ -+ status = ops->jp_init(false); -+ if (status != JP_OK) { -+ xlog(D_GENERAL, "%s: failed to resolve %s: %s", -+ __func__, junction, ops->jp_error(status)); -+ return NULL; -+ } -+ -+ status = ops->jp_get_locations(junction, &locations); -+ if (status != JP_OK) { -+ xlog(D_GENERAL, "%s: failed to resolve %s: %s", -+ __func__, junction, ops->jp_error(status)); -+ return NULL; -+ } -+ -+ exp = locations_to_export(ops, locations, junction); -+ -+ ops->jp_put_locations(locations); -+ ops->jp_done(); -+ return exp; -+} -+ -+/* -+ * Load the junction plug-in, then try to resolve "pathname". -+ * Returns pointer to an initialized exportent if "junction" -+ * refers to a junction, or NULL if not. -+ * -+ * Returned exportent points to static memory. -+ */ -+static struct exportent *lookup_junction(const char *pathname) -+{ -+ struct exportent *exp; -+ void *handle; -+ -+ handle = dlopen("libnfsjunct.so", RTLD_NOW); -+ if (handle == NULL) { -+ xlog(D_GENERAL, "%s: dlopen: %s", __func__, dlerror()); -+ return NULL; -+ } -+ (void)dlerror(); /* Clear any error */ -+ -+ exp = invoke_junction_ops(handle, pathname); -+ -+ /* We could leave it loaded to make junction resolution -+ * faster next time. However, if we want to replace the -+ * library, that would require restarting mountd. */ -+ (void)dlclose(handle); -+ return exp; -+} -+#else /* !HAVE_NFS_PLUGIN_H */ -+static inline struct exportent *lookup_junction(const char *UNUSED(pathname)) -+{ -+ return NULL; -+} -+#endif /* !HAVE_NFS_PLUGIN_H */ -+ - static void nfsd_export(FILE *f) - { - /* requests are: -@@ -854,7 +1077,7 @@ static void nfsd_export(FILE *f) - dump_to_cache(f, dom, path, NULL); - } - } else { -- dump_to_cache(f, dom, path, NULL); -+ dump_to_cache(f, dom, path, lookup_junction(path)); - } - out: - xlog(D_CALL, "nfsd_export: found %p path %s", found, path ? path : NULL); -diff --git a/utils/mountd/fsloc.c b/utils/mountd/fsloc.c -index e2add2d..704b7a0 100644 ---- a/utils/mountd/fsloc.c -+++ b/utils/mountd/fsloc.c -@@ -40,12 +40,12 @@ static void replicas_print(struct servers *sp) - { - int i; - if (!sp) { -- xlog(L_NOTICE, "NULL replicas pointer\n"); -+ xlog(L_NOTICE, "NULL replicas pointer"); - return; - } -- xlog(L_NOTICE, "replicas listsize=%i\n", sp->h_num); -+ xlog(L_NOTICE, "replicas listsize=%i", sp->h_num); - for (i=0; ih_num; i++) { -- xlog(L_NOTICE, " %s:%s\n", -+ xlog(L_NOTICE, " %s:%s", - sp->h_mp[i]->h_host, sp->h_mp[i]->h_path); - } - } -@@ -125,13 +125,13 @@ static struct servers *method_list(char *data) - int i, listsize; - struct servers *rv=NULL; - -- xlog(L_NOTICE, "method_list(%s)\n", data); -+ xlog(L_NOTICE, "method_list(%s)", data); - for (ptr--, listsize=1; ptr; ptr=index(ptr, ':'), listsize++) - ptr++; - list = malloc(listsize * sizeof(char *)); - copy = strdup(data); - if (copy) -- xlog(L_NOTICE, "converted to %s\n", copy); -+ xlog(L_NOTICE, "converted to %s", copy); - if (list && copy) { - ptr = copy; - for (i=0; im_export; - - dupexportent(&eep, &pseudo_root.m_export); -- eep.e_hostname = strdup(curexp->e_hostname); -+ eep.e_hostname = curexp->e_hostname; - strncpy(eep.e_path, path, sizeof(eep.e_path)); - if (strcmp(path, "/") != 0) - eep.e_flags &= ~NFSEXP_FSID; -diff --git a/utils/nfsd/nfsd.man b/utils/nfsd/nfsd.man -index d8988d2..1cf9296 100644 ---- a/utils/nfsd/nfsd.man -+++ b/utils/nfsd/nfsd.man -@@ -38,7 +38,7 @@ request on all known network addresses. This may change in future - releases of the Linux Kernel. - .TP - .B \-p " or " \-\-port port --specify a diferent port to listen on for NFS requests. By default, -+specify a different port to listen on for NFS requests. By default, - .B rpc.nfsd - will listen on port 2049. - .TP -diff --git a/utils/nfsidmap/Makefile.am b/utils/nfsidmap/Makefile.am -index f837b91..c0675c4 100644 ---- a/utils/nfsidmap/Makefile.am -+++ b/utils/nfsidmap/Makefile.am -@@ -4,6 +4,6 @@ man8_MANS = nfsidmap.man - - sbin_PROGRAMS = nfsidmap - nfsidmap_SOURCES = nfsidmap.c --nfsidmap_LDADD = -lnfsidmap -lkeyutils -+nfsidmap_LDADD = $(LIBNFSIDMAP) -lkeyutils ../../support/nfs/libnfs.a - - MAINTAINERCLEANFILES = Makefile.in -diff --git a/utils/nfsidmap/nfsidmap.c b/utils/nfsidmap/nfsidmap.c -index 2d87381..ce8cf3e 100644 ---- a/utils/nfsidmap/nfsidmap.c -+++ b/utils/nfsidmap/nfsidmap.c -@@ -9,15 +9,25 @@ - #include - #include - --#include -+#include -+#include "xlog.h" - --/* gcc nfsidmap.c -o nfsidmap -l nfsidmap -l keyutils */ -+int verbose = 0; -+char *usage="Usage: %s [-v] [-c || [-u|-g|-r key] || [-t timeout] key desc]"; - - #define MAX_ID_LEN 11 - #define IDMAP_NAMESZ 128 - #define USER 1 - #define GROUP 0 - -+#define PROCKEYS "/proc/keys" -+#ifndef DEFAULT_KEYRING -+#define DEFAULT_KEYRING "id_resolver" -+#endif -+ -+ -+#define UIDKEYS 0x1 -+#define GIDKEYS 0x2 - - /* - * Find either a user or group id based on the name@domain string -@@ -36,9 +46,15 @@ int id_lookup(char *name_at_domain, key_serial_t key, int type) - rc = nfs4_group_owner_to_gid(name_at_domain, &gid); - sprintf(id, "%u", gid); - } -+ if (rc < 0) -+ xlog_err("id_lookup: %s: failed: %m", -+ (type == USER ? "nfs4_owner_to_uid" : "nfs4_group_owner_to_gid")); - -- if (rc == 0) -+ if (rc == 0) { - rc = keyctl_instantiate(key, id, strlen(id) + 1, 0); -+ if (rc < 0) -+ xlog_err("id_lookup: keyctl_instantiate failed: %m"); -+ } - - return rc; - } -@@ -57,6 +73,7 @@ int name_lookup(char *id, key_serial_t key, int type) - rc = nfs4_get_default_domain(NULL, domain, NFS4_MAX_DOMAIN_LEN); - if (rc != 0) { - rc = -1; -+ xlog_err("name_lookup: nfs4_get_default_domain failed: %m"); - goto out; - } - -@@ -67,39 +84,206 @@ int name_lookup(char *id, key_serial_t key, int type) - gid = atoi(id); - rc = nfs4_gid_to_name(gid, domain, name, IDMAP_NAMESZ); - } -+ if (rc < 0) -+ xlog_err("name_lookup: %s: failed: %m", -+ (type == USER ? "nfs4_uid_to_name" : "nfs4_gid_to_name")); - -- if (rc == 0) -+ if (rc == 0) { - rc = keyctl_instantiate(key, &name, strlen(name), 0); -- -+ if (rc < 0) -+ xlog_err("name_lookup: keyctl_instantiate failed: %m"); -+ } - out: - return rc; - } -+/* -+ * Clear all the keys on the given keyring -+ */ -+static int keyring_clear(char *keyring) -+{ -+ FILE *fp; -+ char buf[BUFSIZ]; -+ key_serial_t key; -+ -+ xlog_syslog(0); -+ if (keyring == NULL) -+ keyring = DEFAULT_KEYRING; -+ -+ if ((fp = fopen(PROCKEYS, "r")) == NULL) { -+ xlog_err("fopen(%s) failed: %m", PROCKEYS); -+ return 1; -+ } -+ -+ while(fgets(buf, BUFSIZ, fp) != NULL) { -+ if (strstr(buf, "keyring") == NULL) -+ continue; -+ if (strstr(buf, keyring) == NULL) -+ continue; -+ if (verbose) { -+ *(strchr(buf, '\n')) = '\0'; -+ xlog_warn("clearing '%s'", buf); -+ } -+ /* -+ * The key is the first arugment in the string -+ */ -+ *(strchr(buf, ' ')) = '\0'; -+ sscanf(buf, "%x", &key); -+ if (keyctl_clear(key) < 0) { -+ xlog_err("keyctl_clear(0x%x) failed: %m", key); -+ fclose(fp); -+ return 1; -+ } -+ fclose(fp); -+ return 0; -+ } -+ xlog_err("'%s' keyring was not found.", keyring); -+ fclose(fp); -+ return 1; -+} -+/* -+ * Revoke a key -+ */ -+static int key_revoke(char *keystr, int keymask) -+{ -+ FILE *fp; -+ char buf[BUFSIZ], *ptr; -+ key_serial_t key; -+ int mask; -+ -+ xlog_syslog(0); -+ -+ if ((fp = fopen(PROCKEYS, "r")) == NULL) { -+ xlog_err("fopen(%s) failed: %m", PROCKEYS); -+ return 1; -+ } -+ -+ while(fgets(buf, BUFSIZ, fp) != NULL) { -+ if (strstr(buf, "keyring") != NULL) -+ continue; -+ -+ mask = 0; -+ if ((ptr = strstr(buf, "uid:")) != NULL) -+ mask = UIDKEYS; -+ else if ((ptr = strstr(buf, "gid:")) != NULL) -+ mask = GIDKEYS; -+ else -+ continue; -+ -+ if ((keymask & mask) == 0) -+ continue; -+ -+ if (strncmp(ptr+4, keystr, strlen(keystr)) != NULL) -+ continue; -+ -+ if (verbose) { -+ *(strchr(buf, '\n')) = '\0'; -+ xlog_warn("revoking '%s'", buf); -+ } -+ /* -+ * The key is the first arugment in the string -+ */ -+ *(strchr(buf, ' ')) = '\0'; -+ sscanf(buf, "%x", &key); -+ -+ if (keyctl_revoke(key) < 0) { -+ xlog_err("keyctl_revoke(0x%x) failed: %m", key); -+ fclose(fp); -+ return 1; -+ } -+ -+ keymask &= ~mask; -+ if (keymask == 0) { -+ fclose(fp); -+ return 0; -+ } -+ } -+ xlog_err("'%s' key was not found.", keystr); -+ fclose(fp); -+ return 1; -+} - - int main(int argc, char **argv) - { - char *arg; - char *value; - char *type; -- int rc = 1; -+ int rc = 1, opt; - int timeout = 600; - key_serial_t key; -+ char *progname, *keystr = NULL; -+ int clearing = 0, keymask = 0; -+ -+ /* Set the basename */ -+ if ((progname = strrchr(argv[0], '/')) != NULL) -+ progname++; -+ else -+ progname = argv[0]; - -- if (argc < 3) -+ xlog_open(progname); -+ -+ while ((opt = getopt(argc, argv, "u:g:r:ct:v")) != -1) { -+ switch (opt) { -+ case 'u': -+ keymask = UIDKEYS; -+ keystr = strdup(optarg); -+ break; -+ case 'g': -+ keymask = GIDKEYS; -+ keystr = strdup(optarg); -+ break; -+ case 'r': -+ keymask = GIDKEYS|UIDKEYS; -+ keystr = strdup(optarg); -+ break; -+ case 'c': -+ clearing++; -+ break; -+ case 'v': -+ verbose++; -+ break; -+ case 't': -+ timeout = atoi(optarg); -+ break; -+ default: -+ xlog_warn(usage, progname); -+ break; -+ } -+ } -+ -+ if (keystr) { -+ rc = key_revoke(keystr, keymask); -+ return rc; -+ } -+ if (clearing) { -+ rc = keyring_clear(DEFAULT_KEYRING); -+ return rc; -+ } -+ -+ xlog_stderr(0); -+ if ((argc - optind) != 2) { -+ xlog_err("Bad arg count. Check /etc/request-key.conf"); -+ xlog_warn(usage, progname); - return 1; -+ } -+ -+ if (verbose) -+ nfs4_set_debug(verbose, NULL); -+ -+ key = strtol(argv[optind++], NULL, 10); - -- arg = malloc(sizeof(char) * strlen(argv[2]) + 1); -- strcpy(arg, argv[2]); -+ arg = strdup(argv[optind]); -+ if (arg == NULL) { -+ xlog_err("strdup failed: %m"); -+ return 1; -+ } - type = strtok(arg, ":"); - value = strtok(NULL, ":"); - -- if (argc == 4) { -- timeout = atoi(argv[3]); -- if (timeout < 0) -- timeout = 0; -+ if (verbose) { -+ xlog_warn("key: %ld type: %s value: %s timeout %ld", -+ key, type, value, timeout); - } - -- key = strtol(argv[1], NULL, 10); -- - if (strcmp(type, "uid") == 0) - rc = id_lookup(value, key, USER); - else if (strcmp(type, "gid") == 0) -@@ -109,7 +293,7 @@ int main(int argc, char **argv) - else if (strcmp(type, "group") == 0) - rc = name_lookup(value, key, GROUP); - -- /* Set timeout to 5 (600 seconds) minutes */ -+ /* Set timeout to 10 (600 seconds) minutes */ - if (rc == 0) - keyctl_set_timeout(key, timeout); - -diff --git a/utils/nfsidmap/nfsidmap.man b/utils/nfsidmap/nfsidmap.man -index 2381908..3a3a523 100644 ---- a/utils/nfsidmap/nfsidmap.man -+++ b/utils/nfsidmap/nfsidmap.man -@@ -5,6 +5,12 @@ - .TH nfsidmap 5 "1 October 2010" - .SH NAME - nfsidmap \- The NFS idmapper upcall program -+.SH SYNOPSIS -+.B "nfsidmap [-v] [-t timeout] key desc" -+.br -+.B "nfsidmap [-v] [-c]" -+.br -+.B "nfsidmap [-v] [-u|-g|-r user]" - .SH DESCRIPTION - The file - .I /usr/sbin/nfsidmap -@@ -12,11 +18,36 @@ is used by the NFS idmapper to translate user and group ids into names, and to - translate user and group names into ids. Idmapper uses request-key to perform - the upcall and cache the result. - .I /usr/sbin/nfsidmap --should only be called by request-key, and will perform the translation and -+is called by /sbin/request-key, and will perform the translation and - initialize a key with the resulting information. - .PP --NFS_USE_NEW_IDMAPPER must be selected when configuring the kernel to use this --feature. -+.I nfsidmap -+can also used to clear the keyring of all the keys or -+revoke one particular key. -+This is useful when the id mappings have failed to due -+to a lookup error resulting in all the cached uids/gids to be set -+to the user id nobody. -+.SH OPTIONS -+.TP -+.B -c -+Clear the keyring of all the keys. -+.TP -+.B -g user -+Revoke the gid key of the given user. -+.TP -+.B -r user -+Revoke both the uid and gid key of the given user. -+.TP -+.B -t timeout -+Set the expiration timer, in seconds, on the key. -+The default is 600 seconds (10 mins). -+.TP -+.B -u user -+Revoke the uid key of the given user. -+.TP -+.B -v -+Increases the verbosity of the output to syslog -+(can be specified multiple times). - .SH CONFIGURING - The file - .I /etc/request-key.conf -@@ -25,11 +56,13 @@ will need to be modified so - can properly direct the upcall. The following line should be added before a call - to keyctl negate: - .PP --create id_resolver * * /usr/sbin/nfsidmap %k %d 600 -+create id_resolver * * /usr/sbin/nfsidmap -t 600 %k %d - .PP - This will direct all id_resolver requests to the program --.I /usr/sbin/nfsidmap --The last parameter, 600, defines how many seconds into the future the key will -+.I /usr/sbin/nfsidmap. -+The -+.B -t 600 -+defines how many seconds into the future the key will - expire. This is an optional parameter for - .I /usr/sbin/nfsidmap - and will default to 600 seconds when not specified. -@@ -48,9 +81,9 @@ You can choose to handle any of these individually, rather than using the - generic upcall program. If you would like to use your own program for a uid - lookup then you would edit your request-key.conf so it looks similar to this: - .PP --create id_resolver uid:* * /some/other/program %k %d 600 -+create id_resolver uid:* * /some/other/program %k %d - .br --create id_resolver * * /usr/sbin/nfsidmap %k %d 600 -+create id_resolver * * /usr/sbin/nfsidmap %k %d - .PP - Notice that the new line was added above the line for the generic program. - request-key will find the first matching line and run the corresponding program. diff --git a/nfs-utils-1.2.6-rc6.patch b/nfs-utils-1.2.6-rc6.patch deleted file mode 100644 index 8670a1c..0000000 --- a/nfs-utils-1.2.6-rc6.patch +++ /dev/null @@ -1,1257 +0,0 @@ -diff --git a/aclocal/ipv6.m4 b/aclocal/ipv6.m4 -index 5ee8fb6..75a8582 100644 ---- a/aclocal/ipv6.m4 -+++ b/aclocal/ipv6.m4 -@@ -2,11 +2,6 @@ dnl Checks for IPv6 support - dnl - AC_DEFUN([AC_IPV6], [ - -- AC_CHECK_DECL([AI_ADDRCONFIG], -- [AC_DEFINE([HAVE_DECL_AI_ADDRCONFIG], 1, -- [Define this to 1 if AI_ADDRCONFIG macro is defined])], , -- [ #include ]) -- - if test "$enable_ipv6" = yes; then - - dnl TI-RPC required for IPv6 -@@ -15,15 +10,11 @@ AC_DEFUN([AC_IPV6], [ - fi - - dnl IPv6-enabled networking functions required for IPv6 -- AC_CHECK_FUNCS([getifaddrs getnameinfo bindresvport_sa], , -+ AC_CHECK_FUNCS([getifaddrs getnameinfo], , - [AC_MSG_ERROR([Missing library functions needed for IPv6.])]) - -- dnl Need to detect presence of IPv6 networking at run time via -- dnl getaddrinfo(3); old versions of glibc do not support ADDRCONFIG -- AC_CHECK_DECL([AI_ADDRCONFIG], , -- [AC_MSG_ERROR([full getaddrinfo(3) implementation needed for IPv6 support])], -- [ #include ]) -- -+ AC_CHECK_LIB([tirpc], [bindresvport_sa], [:], -+ [AC_MSG_ERROR([Missing library functions needed for IPv6.])]) - fi - - ])dnl -diff --git a/aclocal/libevent.m4 b/aclocal/libevent.m4 -index 3c962b3..b5ac00f 100644 ---- a/aclocal/libevent.m4 -+++ b/aclocal/libevent.m4 -@@ -2,8 +2,9 @@ dnl Checks for libevent - AC_DEFUN([AC_LIBEVENT], [ - - dnl Check for libevent, but do not add -levent to LIBS -- AC_CHECK_LIB([event], [event_dispatch], [libevent=1], -+ AC_CHECK_LIB([event], [event_dispatch], [LIBEVENT=-levent], - [AC_MSG_ERROR([libevent not found.])]) -+ AC_SUBST(LIBEVENT) - - AC_CHECK_HEADERS([event.h], , - [AC_MSG_ERROR([libevent headers not found.])]) -diff --git a/aclocal/libnfsidmap.m4 b/aclocal/libnfsidmap.m4 -index 484b1ec..ae697e8 100644 ---- a/aclocal/libnfsidmap.m4 -+++ b/aclocal/libnfsidmap.m4 -@@ -3,7 +3,7 @@ dnl - AC_DEFUN([AC_LIBNFSIDMAP], [ - - dnl Check for libnfsidmap, but do not add -lnfsidmap to LIBS -- AC_CHECK_LIB([nfsidmap], [nfs4_init_name_mapping], [libnfsidmap=1], -+ AC_CHECK_LIB([nfsidmap], [nfs4_init_name_mapping], [LIBNFSIDMAP=-lnfsidmap], - [AC_MSG_ERROR([libnfsidmap not found.])]) - - AC_CHECK_HEADERS([nfsidmap.h], , -@@ -14,7 +14,10 @@ AC_DEFUN([AC_LIBNFSIDMAP], [ - [AC_DEFINE([HAVE_NFS4_SET_DEBUG], 1, - [Define to 1 if you have the `nfs4_set_debug' function.])]) - -- dnl only enable nfsidmap when libnfsidmap supports it -- AC_CHECK_LIB([nfsidmap], [nfs4_owner_to_uid]) -+ dnl nfs4_owner_to_uid() doesn't appear in all versions of libnfsidmap -+ dnl We just need this test to set $ac_cv_lib_nfsidmap_nfs4_owner_to_uid -+ AC_CHECK_LIB([nfsidmap], [nfs4_owner_to_uid], [:]) -+ -+ AC_SUBST(LIBNFSIDMAP) - - ])dnl -diff --git a/aclocal/libtirpc.m4 b/aclocal/libtirpc.m4 -index 9f0fde0..19b8361 100644 ---- a/aclocal/libtirpc.m4 -+++ b/aclocal/libtirpc.m4 -@@ -13,8 +13,8 @@ AC_DEFUN([AC_LIBTIRPC], [ - - if test "$enable_tirpc" != "no"; then - -- dnl look for the library; add to LIBS if found -- AC_CHECK_LIB([tirpc], [clnt_tli_create], , -+ dnl look for the library -+ AC_CHECK_LIB([tirpc], [clnt_tli_create], [:], - [if test "$enable_tirpc" = "yes"; then - AC_MSG_ERROR([libtirpc not found.]) - else -@@ -37,4 +37,15 @@ AC_DEFUN([AC_LIBTIRPC], [ - - fi - -+ dnl now set $LIBTIRPC accordingly -+ if test "$enable_tirpc" != "no"; then -+ AC_DEFINE([HAVE_LIBTIRPC], 1, -+ [Define to 1 if you have and wish to use libtirpc.]) -+ LIBTIRPC="-ltirpc" -+ else -+ LIBTIRPC="" -+ fi -+ -+ AC_SUBST(LIBTIRPC) -+ - ])dnl -diff --git a/configure.ac b/configure.ac -index 80fb39d..920e8da 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -24,9 +24,8 @@ AC_ARG_WITH(statedir, - statedir=/var/lib/nfs) - AC_SUBST(statedir) - AC_ARG_WITH(statdpath, -- [AC_HELP_STRING([--with-statdpath=/foo @<:@default=/var/lib/nfs@:>@], -- [define statd's state dir as /foo instead of the NFS statedir] -- )], -+ [AC_HELP_STRING([--with-statdpath=/foo], -+ [define the statd state dir as /foo instead of the NFS statedir @<:@default=/var/lib/nfs@:>@])], - statdpath=$withval, - statdpath=$statedir - ) -@@ -249,6 +248,8 @@ AC_CHECK_FUNC([getservbyname], , - - AC_CHECK_LIB([crypt], [crypt], [LIBCRYPT="-lcrypt"]) - -+AC_CHECK_LIB([dl], [dlclose], [LIBDL="-ldl"]) -+ - if test "$enable_nfsv4" = yes; then - dnl check for libevent libraries and headers - AC_LIBEVENT -@@ -265,6 +266,12 @@ if test "$enable_nfsv4" = yes; then - AC_RPCSEC_VERSION - fi - fi -+ -+if test "$enable_nfsv41" = yes; then -+ AC_CHECK_LIB([devmapper], [dm_task_create], [LIBDEVMAPPER="-ldevmapper"], AC_MSG_ERROR([libdevmapper needed])) -+ AC_CHECK_HEADER(libdevmapper.h, , AC_MSG_ERROR([Cannot find devmapper header file libdevmapper.h])) -+fi -+ - dnl enable nfsidmap when its support by libnfsidmap - AM_CONDITIONAL(CONFIG_NFSIDMAP, [test "$ac_cv_header_keyutils_h$ac_cv_lib_nfsidmap_nfs4_owner_to_uid" = "yesyes"]) - -@@ -293,6 +300,7 @@ AC_SUBST(LIBSOCKET) - AC_SUBST(LIBCRYPT) - AC_SUBST(LIBBSD) - AC_SUBST(LIBBLKID) -+AC_SUBST(LIBDL) - - if test "$enable_libmount" != no; then - AC_CHECK_LIB(mount, mnt_context_do_mount, [LIBMOUNT="-lmount"], AC_MSG_ERROR([libmount needed])) -@@ -330,7 +338,7 @@ AC_CHECK_HEADERS([arpa/inet.h fcntl.h libintl.h limits.h \ - stdlib.h string.h sys/file.h sys/ioctl.h sys/mount.h \ - sys/param.h sys/socket.h sys/time.h sys/vfs.h \ - syslog.h unistd.h com_err.h et/com_err.h \ -- ifaddrs.h]) -+ ifaddrs.h nfs-plugin.h]) - - dnl ************************************************************* - dnl Checks for typedefs, structures, and compiler characteristics -diff --git a/support/include/nfs/debug.h b/support/include/nfs/debug.h -index d391e91..dbec5ba 100644 ---- a/support/include/nfs/debug.h -+++ b/support/include/nfs/debug.h -@@ -76,6 +76,9 @@ enum { - #define NFSDBG_CALLBACK 0x0100 - #define NFSDBG_CLIENT 0x0200 - #define NFSDBG_MOUNT 0x0400 -+#define NFSDBG_FSCACHE 0x0800 -+#define NFSDBG_PNFS 0x1000 -+#define NFSDBG_PNFS_LD 0x2000 - #define NFSDBG_ALL 0xFFFF - - #endif /* _NFS_DEBUG_H */ -diff --git a/support/nfs/conffile.c b/support/nfs/conffile.c -index fa0dc6b..3990578 100644 ---- a/support/nfs/conffile.c -+++ b/support/nfs/conffile.c -@@ -256,13 +256,14 @@ conf_parse_line(int trans, char *line, size_t sz) - val++, j++; - if (*val) - i = j; -- section = malloc(i); -+ section = malloc(i+1); - if (!section) { - xlog_warn("conf_parse_line: %d: malloc (%lu) failed", ln, - (unsigned long)i); - return; - } - strncpy(section, line, i); -+ section[i] = '\0'; - - if (arg) - free(arg); -diff --git a/support/nfs/nfsctl.c b/support/nfs/nfsctl.c -index 89fa1a4..fec775f 100644 ---- a/support/nfs/nfsctl.c -+++ b/support/nfs/nfsctl.c -@@ -11,16 +11,22 @@ - #endif - - #include -+#include - #include - #include "nfslib.h" - - /* compatibility hack... */ --#ifndef __NR_nfsctl -+#if !defined(__NR_nfsctl) && defined(__NR_nfsservctl) - #define __NR_nfsctl __NR_nfsservctl - #endif - - int - nfsctl (int cmd, struct nfsctl_arg * argp, union nfsctl_res * resp) - { -+#ifdef __NR_nfsctl - return syscall (__NR_nfsctl, cmd, argp, resp); -+#else -+ errno = ENOSYS; -+ return -1; -+#endif - } -diff --git a/tools/rpcdebug/rpcdebug.c b/tools/rpcdebug/rpcdebug.c -index 275a491..444616d 100644 ---- a/tools/rpcdebug/rpcdebug.c -+++ b/tools/rpcdebug/rpcdebug.c -@@ -167,6 +167,9 @@ static struct flagmap { - FLAG(NFS, CALLBACK), - FLAG(NFS, CLIENT), - FLAG(NFS, MOUNT), -+ FLAG(NFS, FSCACHE), -+ FLAG(NFS, PNFS), -+ FLAG(NFS, PNFS_LD), - FLAG(NFS, ALL), - - /* nfsd */ -diff --git a/tools/rpcgen/Makefile.am b/tools/rpcgen/Makefile.am -index 51a2bfa..8a9ec89 100644 ---- a/tools/rpcgen/Makefile.am -+++ b/tools/rpcgen/Makefile.am -@@ -12,6 +12,7 @@ rpcgen_SOURCES = rpc_clntout.c rpc_cout.c rpc_hout.c rpc_main.c \ - rpcgen_CFLAGS=$(CFLAGS_FOR_BUILD) - rpcgen_CPPLAGS=$(CPPFLAGS_FOR_BUILD) - rpcgen_LDFLAGS=$(LDFLAGS_FOR_BUILD) -+rpcgen_LDADD=$(LIBTIRPC) - - MAINTAINERCLEANFILES = Makefile.in - -diff --git a/utils/blkmapd/device-process.c b/utils/blkmapd/device-process.c -index 27ff374..652a7a8 100644 ---- a/utils/blkmapd/device-process.c -+++ b/utils/blkmapd/device-process.c -@@ -296,7 +296,7 @@ decode_blk_volume(uint32_t **pp, uint32_t *end, struct bl_volume *vols, int voln - off_t stripe_unit = vol->param.bv_stripe_unit; - /* Check limitations imposed by device-mapper */ - if ((stripe_unit & (stripe_unit - 1)) != 0 -- || stripe_unit < (off_t) (PAGE_SIZE >> 9)) -+ || stripe_unit < (off_t) (sysconf(_SC_PAGE_SIZE) >> 9)) - return -EIO; - BLK_READBUF(p, end, 4); - READ32(vol->bv_vol_n); -diff --git a/utils/exportfs/exportfs.man b/utils/exportfs/exportfs.man -index 364f247..8853486 100644 ---- a/utils/exportfs/exportfs.man -+++ b/utils/exportfs/exportfs.man -@@ -177,7 +177,7 @@ In this way - .B exportfs - can be used to modify the export options of an already exported directory. - .SS Unexporting Directories --The third synopsis shows how to unexported a currently exported directory. -+The third synopsis shows how to unexport a currently exported directory. - When using - .BR "exportfs -ua" , - all entries listed in -diff --git a/utils/exportfs/nfsd.man b/utils/exportfs/nfsd.man -index 7365a1b..47b73be 100644 ---- a/utils/exportfs/nfsd.man -+++ b/utils/exportfs/nfsd.man -@@ -12,7 +12,7 @@ nfsd \- special filesystem for controlling Linux NFS server - .SH DESCRIPTION - The - .B nfsd --filesytem is a special filesystem which provides access to the Linux -+filesystem is a special filesystem which provides access to the Linux - NFS server. The filesystem consists of a single directory which - contains a number of files. These files are actually gateways into - the NFS server. Writing to them can affect the server. Reading from -@@ -86,7 +86,7 @@ should be followed by a newline, with white-space separating the - fields, and octal quoting of special characters. - - On writing this, the program will be able to read back a filehandle --for that path as exported to the given client. The filehandles length -+for that path as exported to the given client. The filehandle's length - will be at most the number of bytes given. - - The filehandle will be represented in hex with a leading '\ex'. -@@ -165,7 +165,7 @@ file. The user-space program might then write - .ti +5 - nfsd 127.0.0.1 1057206953 localhost - .br --to indicate that 127.0.0.1 should map to localhost, atleast for now. -+to indicate that 127.0.0.1 should map to localhost, at least for now. - - If the program uses select(2) or poll(2) to discover if it can read - from the -diff --git a/utils/gssd/Makefile.am b/utils/gssd/Makefile.am -index d7888ad..d29e132 100644 ---- a/utils/gssd/Makefile.am -+++ b/utils/gssd/Makefile.am -@@ -40,7 +40,7 @@ gssd_SOURCES = \ - - gssd_LDADD = ../../support/nfs/libnfs.a \ - $(RPCSECGSS_LIBS) $(GSSGLUE_LIBS) $(KRBLIBS) --gssd_LDFLAGS = $(KRBLDFLAGS) -+gssd_LDFLAGS = $(KRBLDFLAGS) $(LIBTIRPC) - - gssd_CFLAGS = $(AM_CFLAGS) $(CFLAGS) \ - $(RPCSECGSS_CFLAGS) $(GSSGLUE_CFLAGS) $(KRBCFLAGS) -@@ -58,8 +58,8 @@ svcgssd_SOURCES = \ - - svcgssd_LDADD = \ - ../../support/nfs/libnfs.a \ -- $(RPCSECGSS_LIBS) $(GSSGLUE_LIBS) -lnfsidmap \ -- $(KRBLIBS) -+ $(RPCSECGSS_LIBS) $(GSSGLUE_LIBS) $(LIBNFSIDMAP) \ -+ $(KRBLIBS) $(LIBTIRPC) - - svcgssd_LDFLAGS = $(KRBLDFLAGS) - -diff --git a/utils/gssd/context_lucid.c b/utils/gssd/context_lucid.c -index 3e695ab..64146d7 100644 ---- a/utils/gssd/context_lucid.c -+++ b/utils/gssd/context_lucid.c -@@ -80,6 +80,7 @@ prepare_krb5_rfc1964_buffer(gss_krb5_lucid_context_v1_t *lctx, - uint32_t i; - char *skd, *dkd; - gss_buffer_desc fakeoid; -+ int err; - - /* - * The new Kerberos interface to get the gss context -@@ -138,11 +139,10 @@ prepare_krb5_rfc1964_buffer(gss_krb5_lucid_context_v1_t *lctx, - dkd = (char *) enc_key.data; - for (i = 0; i < enc_key.length; i++) - dkd[i] = skd[i] ^ 0xf0; -- if (write_lucid_keyblock(&p, end, &enc_key)) { -- free(enc_key.data); -- goto out_err; -- } -+ err = write_lucid_keyblock(&p, end, &enc_key); - free(enc_key.data); -+ if (err) -+ goto out_err; - - if (write_lucid_keyblock(&p, end, &lctx->rfc1964_kd.ctx_key)) - goto out_err; -@@ -153,7 +153,6 @@ out_err: - printerr(0, "ERROR: failed serializing krb5 context for kernel\n"); - if (buf->value) free(buf->value); - buf->length = 0; -- if (enc_key.data) free(enc_key.data); - return -1; - } - -diff --git a/utils/idmapd/Makefile.am b/utils/idmapd/Makefile.am -index 4328e41..58b33ec 100644 ---- a/utils/idmapd/Makefile.am -+++ b/utils/idmapd/Makefile.am -@@ -16,7 +16,7 @@ idmapd_SOURCES = \ - nfs_idmap.h \ - queue.h - --idmapd_LDADD = -levent -lnfsidmap ../../support/nfs/libnfs.a -+idmapd_LDADD = $(LIBEVENT) $(LIBNFSIDMAP) ../../support/nfs/libnfs.a - - MAINTAINERCLEANFILES = Makefile.in - -diff --git a/utils/idmapd/idmapd.c b/utils/idmapd/idmapd.c -index 19d9114..e80efb4 100644 ---- a/utils/idmapd/idmapd.c -+++ b/utils/idmapd/idmapd.c -@@ -778,8 +778,8 @@ nfsopen(struct idmap_client *ic) - } else { - event_set(&ic->ic_event, ic->ic_fd, EV_READ, nfscb, ic); - event_add(&ic->ic_event, NULL); -- fcntl(ic->ic_dirfd, F_SETSIG, 0); - fcntl(ic->ic_dirfd, F_NOTIFY, 0); -+ fcntl(ic->ic_dirfd, F_SETSIG, 0); - if (verbose > 0) - xlog_warn("Opened %s", ic->ic_path); - } -diff --git a/utils/mount/Makefile.am b/utils/mount/Makefile.am -index 7bc3e2b..7627854 100644 ---- a/utils/mount/Makefile.am -+++ b/utils/mount/Makefile.am -@@ -24,7 +24,8 @@ EXTRA_DIST += nfsmount.conf - endif - - mount_nfs_LDADD = ../../support/nfs/libnfs.a \ -- ../../support/export/libexport.a -+ ../../support/export/libexport.a \ -+ $(LIBTIRPC) - - mount_nfs_SOURCES = $(mount_common) - -diff --git a/utils/mount/mount_libmount.c b/utils/mount/mount_libmount.c -index e450d79..e8f17a9 100644 ---- a/utils/mount/mount_libmount.c -+++ b/utils/mount/mount_libmount.c -@@ -346,6 +346,21 @@ static int mount_main(struct libmnt_context *cxt, int argc, char **argv) - - if (chk_mountpoint(mount_point)) - goto err; -+ -+ /* -+ * The libmount strictly uses only options from fstab if running in -+ * restricted mode (suid, non-root user). This is done in -+ * mnt_context_prepare_mount() by default. -+ * -+ * We have to read fstab before nfsmount.conf, otherwise the options -+ * from nfsmount.conf will be ignored (overwrited). -+ */ -+ rc = mnt_context_apply_fstab(cxt); -+ if (rc) { -+ nfs_error(_("%s: failed to apply fstab options\n"), progname); -+ goto err; -+ } -+ - /* - * Concatenate mount options from the configuration file - */ -diff --git a/utils/mount/nfs.man b/utils/mount/nfs.man -index ce40933..2ad92d1 100644 ---- a/utils/mount/nfs.man -+++ b/utils/mount/nfs.man -@@ -1561,10 +1561,10 @@ To ensure that the saved mount options are not erased during a remount, - specify either the local mount directory, or the server hostname and - export pathname, but not both, during a remount. For example, - .P --.NF --.TA 2.5i -+.nf -+.ta 8n - mount -o remount,ro /mnt --.FI -+.fi - .P - merges the mount option - .B ro -diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c -index 314a806..d52e21a 100644 ---- a/utils/mount/stropts.c -+++ b/utils/mount/stropts.c -@@ -540,6 +540,8 @@ nfs_rewrite_pmap_mount_options(struct mount_options *options) - errno = EOPNOTSUPP; - else if (rpc_createerr.cf_stat == RPC_AUTHERROR) - errno = EACCES; -+ else if (rpc_createerr.cf_stat == RPC_TIMEDOUT) -+ errno = ETIMEDOUT; - else if (rpc_createerr.cf_error.re_errno != 0) - errno = rpc_createerr.cf_error.re_errno; - return 0; -@@ -665,9 +667,10 @@ static int nfs_try_mount_v3v2(struct nfsmount_info *mi) - case EHOSTUNREACH: - continue; - default: -- break; -+ goto out; - } - } -+out: - return ret; - } - -@@ -751,9 +754,10 @@ static int nfs_try_mount_v4(struct nfsmount_info *mi) - case EHOSTUNREACH: - continue; - default: -- break; -+ goto out; - } - } -+out: - return ret; - } - -diff --git a/utils/mountd/Makefile.am b/utils/mountd/Makefile.am -index eba81fc..7db968b 100644 ---- a/utils/mountd/Makefile.am -+++ b/utils/mountd/Makefile.am -@@ -12,7 +12,7 @@ mountd_SOURCES = mountd.c mount_dispatch.c auth.c rmtab.c cache.c \ - mountd_LDADD = ../../support/export/libexport.a \ - ../../support/nfs/libnfs.a \ - ../../support/misc/libmisc.a \ -- $(LIBBSD) $(LIBWRAP) $(LIBNSL) $(LIBBLKID) -+ $(LIBBSD) $(LIBWRAP) $(LIBNSL) $(LIBBLKID) $(LIBDL) $(LIBTIRPC) - mountd_CPPFLAGS = $(AM_CPPFLAGS) $(CPPFLAGS) \ - -I$(top_builddir)/support/include \ - -I$(top_srcdir)/support/export -diff --git a/utils/mountd/cache.c b/utils/mountd/cache.c -index d2ae456..ac9cdbd 100644 ---- a/utils/mountd/cache.c -+++ b/utils/mountd/cache.c -@@ -802,6 +802,229 @@ lookup_export(char *dom, char *path, struct addrinfo *ai) - return found; - } - -+#ifdef HAVE_NFS_PLUGIN_H -+#include -+#include -+ -+/* -+ * Walk through a set of FS locations and build a set of export options. -+ * Returns true if all went to plan; otherwise, false. -+ */ -+static _Bool -+locations_to_options(struct jp_ops *ops, nfs_fsloc_set_t locations, -+ char *options, size_t remaining, int *ttl) -+{ -+ char *server, *last_path, *rootpath, *ptr; -+ _Bool seen = false; -+ -+ last_path = NULL; -+ rootpath = NULL; -+ server = NULL; -+ ptr = options; -+ *ttl = 0; -+ -+ for (;;) { -+ enum jp_status status; -+ int len; -+ -+ status = ops->jp_get_next_location(locations, &server, -+ &rootpath, ttl); -+ if (status == JP_EMPTY) -+ break; -+ if (status != JP_OK) { -+ xlog(D_GENERAL, "%s: failed to parse location: %s", -+ __func__, ops->jp_error(status)); -+ goto out_false; -+ } -+ xlog(D_GENERAL, "%s: Location: %s:%s", -+ __func__, server, rootpath); -+ -+ if (last_path && strcmp(rootpath, last_path) == 0) { -+ len = snprintf(ptr, remaining, "+%s", server); -+ if (len < 0) { -+ xlog(D_GENERAL, "%s: snprintf: %m", __func__); -+ goto out_false; -+ } -+ if ((size_t)len >= remaining) { -+ xlog(D_GENERAL, "%s: options buffer overflow", __func__); -+ goto out_false; -+ } -+ remaining -= (size_t)len; -+ ptr += len; -+ } else { -+ if (last_path == NULL) -+ len = snprintf(ptr, remaining, "refer=%s@%s", -+ rootpath, server); -+ else -+ len = snprintf(ptr, remaining, ":%s@%s", -+ rootpath, server); -+ if (len < 0) { -+ xlog(D_GENERAL, "%s: snprintf: %m", __func__); -+ goto out_false; -+ } -+ if ((size_t)len >= remaining) { -+ xlog(D_GENERAL, "%s: options buffer overflow", -+ __func__); -+ goto out_false; -+ } -+ remaining -= (size_t)len; -+ ptr += len; -+ last_path = rootpath; -+ } -+ -+ seen = true; -+ free(rootpath); -+ free(server); -+ } -+ -+ xlog(D_CALL, "%s: options='%s', ttl=%d", -+ __func__, options, *ttl); -+ return seen; -+ -+out_false: -+ free(rootpath); -+ free(server); -+ return false; -+} -+ -+/* -+ * Walk through the set of FS locations and build an exportent. -+ * Returns pointer to an exportent if "junction" refers to a junction. -+ * -+ * Returned exportent points to static memory. -+ */ -+static struct exportent *do_locations_to_export(struct jp_ops *ops, -+ nfs_fsloc_set_t locations, const char *junction, -+ char *options, size_t options_len) -+{ -+ struct exportent *exp; -+ int ttl; -+ -+ if (!locations_to_options(ops, locations, options, options_len, &ttl)) -+ return NULL; -+ -+ exp = mkexportent("*", (char *)junction, options); -+ if (exp == NULL) { -+ xlog(L_ERROR, "%s: Failed to construct exportent", __func__); -+ return NULL; -+ } -+ -+ exp->e_uuid = NULL; -+ exp->e_ttl = ttl; -+ return exp; -+} -+ -+/* -+ * Convert set of FS locations to an exportent. Returns pointer to -+ * an exportent if "junction" refers to a junction. -+ * -+ * Returned exportent points to static memory. -+ */ -+static struct exportent *locations_to_export(struct jp_ops *ops, -+ nfs_fsloc_set_t locations, const char *junction) -+{ -+ struct exportent *exp; -+ char *options; -+ -+ options = malloc(BUFSIZ); -+ if (options == NULL) { -+ xlog(D_GENERAL, "%s: failed to allocate options buffer", -+ __func__); -+ return NULL; -+ } -+ options[0] = '\0'; -+ -+ exp = do_locations_to_export(ops, locations, junction, -+ options, BUFSIZ); -+ -+ free(options); -+ return exp; -+} -+ -+/* -+ * Retrieve locations information in "junction" and dump it to the -+ * kernel. Returns pointer to an exportent if "junction" refers -+ * to a junction. -+ * -+ * Returned exportent points to static memory. -+ */ -+static struct exportent *invoke_junction_ops(void *handle, -+ const char *junction) -+{ -+ nfs_fsloc_set_t locations; -+ struct exportent *exp; -+ enum jp_status status; -+ struct jp_ops *ops; -+ char *error; -+ -+ ops = (struct jp_ops *)dlsym(handle, "nfs_junction_ops"); -+ error = dlerror(); -+ if (error != NULL) { -+ xlog(D_GENERAL, "%s: dlsym(jp_junction_ops): %s", -+ __func__, error); -+ return NULL; -+ } -+ if (ops->jp_api_version != JP_API_VERSION) { -+ xlog(D_GENERAL, "%s: unrecognized junction API version: %u", -+ __func__, ops->jp_api_version); -+ return NULL; -+ } -+ -+ status = ops->jp_init(false); -+ if (status != JP_OK) { -+ xlog(D_GENERAL, "%s: failed to resolve %s: %s", -+ __func__, junction, ops->jp_error(status)); -+ return NULL; -+ } -+ -+ status = ops->jp_get_locations(junction, &locations); -+ if (status != JP_OK) { -+ xlog(D_GENERAL, "%s: failed to resolve %s: %s", -+ __func__, junction, ops->jp_error(status)); -+ return NULL; -+ } -+ -+ exp = locations_to_export(ops, locations, junction); -+ -+ ops->jp_put_locations(locations); -+ ops->jp_done(); -+ return exp; -+} -+ -+/* -+ * Load the junction plug-in, then try to resolve "pathname". -+ * Returns pointer to an initialized exportent if "junction" -+ * refers to a junction, or NULL if not. -+ * -+ * Returned exportent points to static memory. -+ */ -+static struct exportent *lookup_junction(const char *pathname) -+{ -+ struct exportent *exp; -+ void *handle; -+ -+ handle = dlopen("libnfsjunct.so", RTLD_NOW); -+ if (handle == NULL) { -+ xlog(D_GENERAL, "%s: dlopen: %s", __func__, dlerror()); -+ return NULL; -+ } -+ (void)dlerror(); /* Clear any error */ -+ -+ exp = invoke_junction_ops(handle, pathname); -+ -+ /* We could leave it loaded to make junction resolution -+ * faster next time. However, if we want to replace the -+ * library, that would require restarting mountd. */ -+ (void)dlclose(handle); -+ return exp; -+} -+#else /* !HAVE_NFS_PLUGIN_H */ -+static inline struct exportent *lookup_junction(const char *UNUSED(pathname)) -+{ -+ return NULL; -+} -+#endif /* !HAVE_NFS_PLUGIN_H */ -+ - static void nfsd_export(FILE *f) - { - /* requests are: -@@ -854,7 +1077,7 @@ static void nfsd_export(FILE *f) - dump_to_cache(f, dom, path, NULL); - } - } else { -- dump_to_cache(f, dom, path, NULL); -+ dump_to_cache(f, dom, path, lookup_junction(path)); - } - out: - xlog(D_CALL, "nfsd_export: found %p path %s", found, path ? path : NULL); -diff --git a/utils/mountd/fsloc.c b/utils/mountd/fsloc.c -index e2add2d..704b7a0 100644 ---- a/utils/mountd/fsloc.c -+++ b/utils/mountd/fsloc.c -@@ -40,12 +40,12 @@ static void replicas_print(struct servers *sp) - { - int i; - if (!sp) { -- xlog(L_NOTICE, "NULL replicas pointer\n"); -+ xlog(L_NOTICE, "NULL replicas pointer"); - return; - } -- xlog(L_NOTICE, "replicas listsize=%i\n", sp->h_num); -+ xlog(L_NOTICE, "replicas listsize=%i", sp->h_num); - for (i=0; ih_num; i++) { -- xlog(L_NOTICE, " %s:%s\n", -+ xlog(L_NOTICE, " %s:%s", - sp->h_mp[i]->h_host, sp->h_mp[i]->h_path); - } - } -@@ -125,13 +125,13 @@ static struct servers *method_list(char *data) - int i, listsize; - struct servers *rv=NULL; - -- xlog(L_NOTICE, "method_list(%s)\n", data); -+ xlog(L_NOTICE, "method_list(%s)", data); - for (ptr--, listsize=1; ptr; ptr=index(ptr, ':'), listsize++) - ptr++; - list = malloc(listsize * sizeof(char *)); - copy = strdup(data); - if (copy) -- xlog(L_NOTICE, "converted to %s\n", copy); -+ xlog(L_NOTICE, "converted to %s", copy); - if (list && copy) { - ptr = copy; - for (i=0; im_export; - - dupexportent(&eep, &pseudo_root.m_export); -- eep.e_hostname = strdup(curexp->e_hostname); -+ eep.e_hostname = curexp->e_hostname; - strncpy(eep.e_path, path, sizeof(eep.e_path)); - if (strcmp(path, "/") != 0) - eep.e_flags &= ~NFSEXP_FSID; -diff --git a/utils/nfsd/Makefile.am b/utils/nfsd/Makefile.am -index c4c6fb0..1536065 100644 ---- a/utils/nfsd/Makefile.am -+++ b/utils/nfsd/Makefile.am -@@ -8,7 +8,7 @@ KPREFIX = @kprefix@ - sbin_PROGRAMS = nfsd - - nfsd_SOURCES = nfsd.c nfssvc.c --nfsd_LDADD = ../../support/nfs/libnfs.a -+nfsd_LDADD = ../../support/nfs/libnfs.a $(LIBTIRPC) - - MAINTAINERCLEANFILES = Makefile.in - -diff --git a/utils/nfsd/nfsd.man b/utils/nfsd/nfsd.man -index d8988d2..1cf9296 100644 ---- a/utils/nfsd/nfsd.man -+++ b/utils/nfsd/nfsd.man -@@ -38,7 +38,7 @@ request on all known network addresses. This may change in future - releases of the Linux Kernel. - .TP - .B \-p " or " \-\-port port --specify a diferent port to listen on for NFS requests. By default, -+specify a different port to listen on for NFS requests. By default, - .B rpc.nfsd - will listen on port 2049. - .TP -diff --git a/utils/nfsidmap/Makefile.am b/utils/nfsidmap/Makefile.am -index f837b91..c0675c4 100644 ---- a/utils/nfsidmap/Makefile.am -+++ b/utils/nfsidmap/Makefile.am -@@ -4,6 +4,6 @@ man8_MANS = nfsidmap.man - - sbin_PROGRAMS = nfsidmap - nfsidmap_SOURCES = nfsidmap.c --nfsidmap_LDADD = -lnfsidmap -lkeyutils -+nfsidmap_LDADD = $(LIBNFSIDMAP) -lkeyutils ../../support/nfs/libnfs.a - - MAINTAINERCLEANFILES = Makefile.in -diff --git a/utils/nfsidmap/nfsidmap.c b/utils/nfsidmap/nfsidmap.c -index 2d87381..cf11551 100644 ---- a/utils/nfsidmap/nfsidmap.c -+++ b/utils/nfsidmap/nfsidmap.c -@@ -3,21 +3,33 @@ - #include - #include - #include -+#include - - #include - #include - #include - #include - --#include -+#include -+#include "xlog.h" - --/* gcc nfsidmap.c -o nfsidmap -l nfsidmap -l keyutils */ -+int verbose = 0; -+char *usage="Usage: %s [-v] [-c || [-u|-g|-r key] || [-t timeout] key desc]"; - - #define MAX_ID_LEN 11 - #define IDMAP_NAMESZ 128 - #define USER 1 - #define GROUP 0 - -+#define PROCKEYS "/proc/keys" -+#ifndef DEFAULT_KEYRING -+#define DEFAULT_KEYRING "id_resolver" -+#endif -+ -+static int keyring_clear(char *keyring); -+ -+#define UIDKEYS 0x1 -+#define GIDKEYS 0x2 - - /* - * Find either a user or group id based on the name@domain string -@@ -36,9 +48,31 @@ int id_lookup(char *name_at_domain, key_serial_t key, int type) - rc = nfs4_group_owner_to_gid(name_at_domain, &gid); - sprintf(id, "%u", gid); - } -+ if (rc < 0) -+ xlog_err("id_lookup: %s: failed: %m", -+ (type == USER ? "nfs4_owner_to_uid" : "nfs4_group_owner_to_gid")); - -- if (rc == 0) -+ if (rc == 0) { - rc = keyctl_instantiate(key, id, strlen(id) + 1, 0); -+ if (rc < 0) { -+ switch(rc) { -+ case -EDQUOT: -+ case -ENFILE: -+ case -ENOMEM: -+ /* -+ * The keyring is full. Clear the keyring and try again -+ */ -+ rc = keyring_clear(DEFAULT_KEYRING); -+ if (rc == 0) -+ rc = keyctl_instantiate(key, id, strlen(id) + 1, 0); -+ break; -+ default: -+ break; -+ } -+ } -+ if (rc < 0) -+ xlog_err("id_lookup: keyctl_instantiate failed: %m"); -+ } - - return rc; - } -@@ -57,6 +91,7 @@ int name_lookup(char *id, key_serial_t key, int type) - rc = nfs4_get_default_domain(NULL, domain, NFS4_MAX_DOMAIN_LEN); - if (rc != 0) { - rc = -1; -+ xlog_err("name_lookup: nfs4_get_default_domain failed: %m"); - goto out; - } - -@@ -67,39 +102,206 @@ int name_lookup(char *id, key_serial_t key, int type) - gid = atoi(id); - rc = nfs4_gid_to_name(gid, domain, name, IDMAP_NAMESZ); - } -+ if (rc < 0) -+ xlog_err("name_lookup: %s: failed: %m", -+ (type == USER ? "nfs4_uid_to_name" : "nfs4_gid_to_name")); - -- if (rc == 0) -+ if (rc == 0) { - rc = keyctl_instantiate(key, &name, strlen(name), 0); -- -+ if (rc < 0) -+ xlog_err("name_lookup: keyctl_instantiate failed: %m"); -+ } - out: - return rc; - } -+/* -+ * Clear all the keys on the given keyring -+ */ -+static int keyring_clear(char *keyring) -+{ -+ FILE *fp; -+ char buf[BUFSIZ]; -+ key_serial_t key; -+ -+ if (keyring == NULL) -+ keyring = DEFAULT_KEYRING; -+ -+ if ((fp = fopen(PROCKEYS, "r")) == NULL) { -+ xlog_err("fopen(%s) failed: %m", PROCKEYS); -+ return 1; -+ } -+ -+ while(fgets(buf, BUFSIZ, fp) != NULL) { -+ if (strstr(buf, "keyring") == NULL) -+ continue; -+ if (strstr(buf, keyring) == NULL) -+ continue; -+ if (verbose) { -+ *(strchr(buf, '\n')) = '\0'; -+ xlog_warn("clearing '%s'", buf); -+ } -+ /* -+ * The key is the first arugment in the string -+ */ -+ *(strchr(buf, ' ')) = '\0'; -+ sscanf(buf, "%x", &key); -+ if (keyctl_clear(key) < 0) { -+ xlog_err("keyctl_clear(0x%x) failed: %m", key); -+ fclose(fp); -+ return 1; -+ } -+ fclose(fp); -+ return 0; -+ } -+ xlog_err("'%s' keyring was not found.", keyring); -+ fclose(fp); -+ return 1; -+} -+/* -+ * Revoke a key -+ */ -+static int key_revoke(char *keystr, int keymask) -+{ -+ FILE *fp; -+ char buf[BUFSIZ], *ptr; -+ key_serial_t key; -+ int mask; -+ -+ xlog_syslog(0); -+ -+ if ((fp = fopen(PROCKEYS, "r")) == NULL) { -+ xlog_err("fopen(%s) failed: %m", PROCKEYS); -+ return 1; -+ } -+ -+ while(fgets(buf, BUFSIZ, fp) != NULL) { -+ if (strstr(buf, "keyring") != NULL) -+ continue; -+ -+ mask = 0; -+ if ((ptr = strstr(buf, "uid:")) != NULL) -+ mask = UIDKEYS; -+ else if ((ptr = strstr(buf, "gid:")) != NULL) -+ mask = GIDKEYS; -+ else -+ continue; -+ -+ if ((keymask & mask) == 0) -+ continue; -+ -+ if (strncmp(ptr+4, keystr, strlen(keystr)) != 0) -+ continue; -+ -+ if (verbose) { -+ *(strchr(buf, '\n')) = '\0'; -+ xlog_warn("revoking '%s'", buf); -+ } -+ /* -+ * The key is the first arugment in the string -+ */ -+ *(strchr(buf, ' ')) = '\0'; -+ sscanf(buf, "%x", &key); -+ -+ if (keyctl_revoke(key) < 0) { -+ xlog_err("keyctl_revoke(0x%x) failed: %m", key); -+ fclose(fp); -+ return 1; -+ } -+ -+ keymask &= ~mask; -+ if (keymask == 0) { -+ fclose(fp); -+ return 0; -+ } -+ } -+ xlog_err("'%s' key was not found.", keystr); -+ fclose(fp); -+ return 1; -+} - - int main(int argc, char **argv) - { - char *arg; - char *value; - char *type; -- int rc = 1; -+ int rc = 1, opt; - int timeout = 600; - key_serial_t key; -+ char *progname, *keystr = NULL; -+ int clearing = 0, keymask = 0; -+ -+ /* Set the basename */ -+ if ((progname = strrchr(argv[0], '/')) != NULL) -+ progname++; -+ else -+ progname = argv[0]; - -- if (argc < 3) -+ xlog_open(progname); -+ -+ while ((opt = getopt(argc, argv, "u:g:r:ct:v")) != -1) { -+ switch (opt) { -+ case 'u': -+ keymask = UIDKEYS; -+ keystr = strdup(optarg); -+ break; -+ case 'g': -+ keymask = GIDKEYS; -+ keystr = strdup(optarg); -+ break; -+ case 'r': -+ keymask = GIDKEYS|UIDKEYS; -+ keystr = strdup(optarg); -+ break; -+ case 'c': -+ clearing++; -+ break; -+ case 'v': -+ verbose++; -+ break; -+ case 't': -+ timeout = atoi(optarg); -+ break; -+ default: -+ xlog_warn(usage, progname); -+ break; -+ } -+ } -+ -+ if (keystr) { -+ rc = key_revoke(keystr, keymask); -+ return rc; -+ } -+ if (clearing) { -+ xlog_syslog(0); -+ rc = keyring_clear(DEFAULT_KEYRING); -+ return rc; -+ } -+ -+ xlog_stderr(0); -+ if ((argc - optind) != 2) { -+ xlog_err("Bad arg count. Check /etc/request-key.conf"); -+ xlog_warn(usage, progname); - return 1; -+ } -+ -+ if (verbose) -+ nfs4_set_debug(verbose, NULL); -+ -+ key = strtol(argv[optind++], NULL, 10); - -- arg = malloc(sizeof(char) * strlen(argv[2]) + 1); -- strcpy(arg, argv[2]); -+ arg = strdup(argv[optind]); -+ if (arg == NULL) { -+ xlog_err("strdup failed: %m"); -+ return 1; -+ } - type = strtok(arg, ":"); - value = strtok(NULL, ":"); - -- if (argc == 4) { -- timeout = atoi(argv[3]); -- if (timeout < 0) -- timeout = 0; -+ if (verbose) { -+ xlog_warn("key: 0x%lx type: %s value: %s timeout %ld", -+ key, type, value, timeout); - } - -- key = strtol(argv[1], NULL, 10); -- - if (strcmp(type, "uid") == 0) - rc = id_lookup(value, key, USER); - else if (strcmp(type, "gid") == 0) -@@ -109,7 +311,7 @@ int main(int argc, char **argv) - else if (strcmp(type, "group") == 0) - rc = name_lookup(value, key, GROUP); - -- /* Set timeout to 5 (600 seconds) minutes */ -+ /* Set timeout to 10 (600 seconds) minutes */ - if (rc == 0) - keyctl_set_timeout(key, timeout); - -diff --git a/utils/nfsidmap/nfsidmap.man b/utils/nfsidmap/nfsidmap.man -index 2381908..3a3a523 100644 ---- a/utils/nfsidmap/nfsidmap.man -+++ b/utils/nfsidmap/nfsidmap.man -@@ -5,6 +5,12 @@ - .TH nfsidmap 5 "1 October 2010" - .SH NAME - nfsidmap \- The NFS idmapper upcall program -+.SH SYNOPSIS -+.B "nfsidmap [-v] [-t timeout] key desc" -+.br -+.B "nfsidmap [-v] [-c]" -+.br -+.B "nfsidmap [-v] [-u|-g|-r user]" - .SH DESCRIPTION - The file - .I /usr/sbin/nfsidmap -@@ -12,11 +18,36 @@ is used by the NFS idmapper to translate user and group ids into names, and to - translate user and group names into ids. Idmapper uses request-key to perform - the upcall and cache the result. - .I /usr/sbin/nfsidmap --should only be called by request-key, and will perform the translation and -+is called by /sbin/request-key, and will perform the translation and - initialize a key with the resulting information. - .PP --NFS_USE_NEW_IDMAPPER must be selected when configuring the kernel to use this --feature. -+.I nfsidmap -+can also used to clear the keyring of all the keys or -+revoke one particular key. -+This is useful when the id mappings have failed to due -+to a lookup error resulting in all the cached uids/gids to be set -+to the user id nobody. -+.SH OPTIONS -+.TP -+.B -c -+Clear the keyring of all the keys. -+.TP -+.B -g user -+Revoke the gid key of the given user. -+.TP -+.B -r user -+Revoke both the uid and gid key of the given user. -+.TP -+.B -t timeout -+Set the expiration timer, in seconds, on the key. -+The default is 600 seconds (10 mins). -+.TP -+.B -u user -+Revoke the uid key of the given user. -+.TP -+.B -v -+Increases the verbosity of the output to syslog -+(can be specified multiple times). - .SH CONFIGURING - The file - .I /etc/request-key.conf -@@ -25,11 +56,13 @@ will need to be modified so - can properly direct the upcall. The following line should be added before a call - to keyctl negate: - .PP --create id_resolver * * /usr/sbin/nfsidmap %k %d 600 -+create id_resolver * * /usr/sbin/nfsidmap -t 600 %k %d - .PP - This will direct all id_resolver requests to the program --.I /usr/sbin/nfsidmap --The last parameter, 600, defines how many seconds into the future the key will -+.I /usr/sbin/nfsidmap. -+The -+.B -t 600 -+defines how many seconds into the future the key will - expire. This is an optional parameter for - .I /usr/sbin/nfsidmap - and will default to 600 seconds when not specified. -@@ -48,9 +81,9 @@ You can choose to handle any of these individually, rather than using the - generic upcall program. If you would like to use your own program for a uid - lookup then you would edit your request-key.conf so it looks similar to this: - .PP --create id_resolver uid:* * /some/other/program %k %d 600 -+create id_resolver uid:* * /some/other/program %k %d - .br --create id_resolver * * /usr/sbin/nfsidmap %k %d 600 -+create id_resolver * * /usr/sbin/nfsidmap %k %d - .PP - Notice that the new line was added above the line for the generic program. - request-key will find the first matching line and run the corresponding program. -diff --git a/utils/showmount/Makefile.am b/utils/showmount/Makefile.am -index 077b2c7..4ba5ead 100644 ---- a/utils/showmount/Makefile.am -+++ b/utils/showmount/Makefile.am -@@ -7,7 +7,8 @@ sbin_PROGRAMS = showmount - showmount_SOURCES = showmount.c - showmount_LDADD = ../../support/export/libexport.a \ - ../../support/nfs/libnfs.a \ -- ../../support/misc/libmisc.a -+ ../../support/misc/libmisc.a \ -+ $(LIBTIRPC) - showmount_CPPFLAGS = $(AM_CPPFLAGS) $(CPPFLAGS) \ - -I$(top_builddir)/support/export - -diff --git a/utils/statd/Makefile.am b/utils/statd/Makefile.am -index 1744791..dc2bfc4 100644 ---- a/utils/statd/Makefile.am -+++ b/utils/statd/Makefile.am -@@ -15,10 +15,10 @@ BUILT_SOURCES = $(GENFILES) - statd_LDADD = ../../support/nsm/libnsm.a \ - ../../support/nfs/libnfs.a \ - ../../support/misc/libmisc.a \ -- $(LIBWRAP) $(LIBNSL) $(LIBCAP) -+ $(LIBWRAP) $(LIBNSL) $(LIBCAP) $(LIBTIRPC) - sm_notify_LDADD = ../../support/nsm/libnsm.a \ - ../../support/nfs/libnfs.a \ -- $(LIBNSL) $(LIBCAP) -+ $(LIBNSL) $(LIBCAP) $(LIBTIRPC) - - EXTRA_DIST = sim_sm_inter.x $(man8_MANS) COPYRIGHT simulate.c - diff --git a/nfs-utils-1.2.6-rc7.patch b/nfs-utils-1.2.6-rc7.patch deleted file mode 100644 index e702124..0000000 --- a/nfs-utils-1.2.6-rc7.patch +++ /dev/null @@ -1,4192 +0,0 @@ -diff --git a/.gitignore b/.gitignore -index 7bd9921..96f9750 100644 ---- a/.gitignore -+++ b/.gitignore -@@ -49,6 +49,7 @@ utils/rquotad/rquotad - utils/rquotad/rquota.h - utils/rquotad/rquota_xdr.c - utils/showmount/showmount -+utils/nfsdcld/nfsdcld - utils/statd/statd - tools/locktest/testlk - tools/getiversion/getiversion -diff --git a/README b/README -index e7588cf..348f5d4 100644 ---- a/README -+++ b/README -@@ -15,6 +15,8 @@ libraries. They are available from - http://www.citi.umich.edu/projects/nfsv4/linux/libnfsidmap/ - Otherwise use --disable-nfsv4 - -+To use the nfsdcld tracking daemon, nfsv4 support must be enabled, -+and the libsqlite3 development libraries must be installed. - - 1. COMPILING - -@@ -80,7 +82,7 @@ scripts can be written to work correctly. - and starting the nfsd server is not important. - idmapd is only needed for NFSv4 support. - svcgssd is only needed if exportfs NFS filesystem with crypto- -- security (Kerberos or SPKM3). -+ security (Kerberos). - - C/ exportfs -av ; rpc.mountd - It is important that exportfs be run before mountd so that -@@ -106,12 +108,31 @@ scripts can be written to work correctly. - the lock. - rpc.statd is only needed for NFSv2 and NFSv3 support. - -- E/ rpc.nfsd -+ E/ nfsdcld -+ This daemon is only needed on kernels that support the nfsdcld -+ upcall, and only if the legacy client ID tracking isn't used. It -+ is also not needed if the server does not support NFSv4. -+ -+ To determine whether you need this or not, do the following: -+ -+ # cat /proc/fs/nfsd/versions -+ -+ That should yield a list of NFS versions that this kernel supports, -+ if "4" or later is not in that list, or they are prefixed with a "-" -+ then you don't need to run this daemon. Next: -+ -+ # cat /proc/fs/nfsd/nfsv4recoverydir -+ -+ If that file is not present, or the directory that the above command -+ outputs is not present, then this daemon is required in order to -+ support lock recovery by the clients when the server reboots. -+ -+ F/ rpc.nfsd - Starting nfsd will automatically start lockd. The nfs server - will now be fully active and respond to any requests from - clients. - -- F/ sm-notify -+ G/ sm-notify - This will notify any client which might have locks from before - a reboot to try to reclaim their locks. This should start - immediately after rpc.nfsd is started so that clients have a -@@ -130,7 +151,7 @@ scripts can be written to work correctly. - B/ gssd ; idmapd - idmapd should be started before mounting any NFSv4 filesystems. - gssd should be started before mounting any NFS filesystems -- securely (with Kerberos of SPKM3). -+ securely (with Kerberos). - - C/ statd should be run before any NFSv2 or NFSv3 filesystem is - mounted with remote locking (i.e. without -o nolock). -diff --git a/aclocal/ipv6.m4 b/aclocal/ipv6.m4 -index 5ee8fb6..75a8582 100644 ---- a/aclocal/ipv6.m4 -+++ b/aclocal/ipv6.m4 -@@ -2,11 +2,6 @@ dnl Checks for IPv6 support - dnl - AC_DEFUN([AC_IPV6], [ - -- AC_CHECK_DECL([AI_ADDRCONFIG], -- [AC_DEFINE([HAVE_DECL_AI_ADDRCONFIG], 1, -- [Define this to 1 if AI_ADDRCONFIG macro is defined])], , -- [ #include ]) -- - if test "$enable_ipv6" = yes; then - - dnl TI-RPC required for IPv6 -@@ -15,15 +10,11 @@ AC_DEFUN([AC_IPV6], [ - fi - - dnl IPv6-enabled networking functions required for IPv6 -- AC_CHECK_FUNCS([getifaddrs getnameinfo bindresvport_sa], , -+ AC_CHECK_FUNCS([getifaddrs getnameinfo], , - [AC_MSG_ERROR([Missing library functions needed for IPv6.])]) - -- dnl Need to detect presence of IPv6 networking at run time via -- dnl getaddrinfo(3); old versions of glibc do not support ADDRCONFIG -- AC_CHECK_DECL([AI_ADDRCONFIG], , -- [AC_MSG_ERROR([full getaddrinfo(3) implementation needed for IPv6 support])], -- [ #include ]) -- -+ AC_CHECK_LIB([tirpc], [bindresvport_sa], [:], -+ [AC_MSG_ERROR([Missing library functions needed for IPv6.])]) - fi - - ])dnl -diff --git a/aclocal/kerberos5.m4 b/aclocal/kerberos5.m4 -index dfa5738..7574e2d 100644 ---- a/aclocal/kerberos5.m4 -+++ b/aclocal/kerberos5.m4 -@@ -31,7 +31,7 @@ AC_DEFUN([AC_KERBEROS_V5],[ - fi - if test "$K5CONFIG" != ""; then - KRBCFLAGS=`$K5CONFIG --cflags` -- KRBLIBS=`$K5CONFIG --libs gssapi` -+ KRBLIBS=`$K5CONFIG --libs` - K5VERS=`$K5CONFIG --version | head -n 1 | awk '{split($(4),v,"."); if (v@<:@"3"@:>@ == "") v@<:@"3"@:>@ = "0"; print v@<:@"1"@:>@v@<:@"2"@:>@v@<:@"3"@:>@ }'` - AC_DEFINE_UNQUOTED(KRB5_VERSION, $K5VERS, [Define this as the Kerberos version number]) - if test -f $dir/include/gssapi/gssapi_krb5.h -a \ -diff --git a/aclocal/libevent.m4 b/aclocal/libevent.m4 -index 3c962b3..b5ac00f 100644 ---- a/aclocal/libevent.m4 -+++ b/aclocal/libevent.m4 -@@ -2,8 +2,9 @@ dnl Checks for libevent - AC_DEFUN([AC_LIBEVENT], [ - - dnl Check for libevent, but do not add -levent to LIBS -- AC_CHECK_LIB([event], [event_dispatch], [libevent=1], -+ AC_CHECK_LIB([event], [event_dispatch], [LIBEVENT=-levent], - [AC_MSG_ERROR([libevent not found.])]) -+ AC_SUBST(LIBEVENT) - - AC_CHECK_HEADERS([event.h], , - [AC_MSG_ERROR([libevent headers not found.])]) -diff --git a/aclocal/libnfsidmap.m4 b/aclocal/libnfsidmap.m4 -index 484b1ec..ae697e8 100644 ---- a/aclocal/libnfsidmap.m4 -+++ b/aclocal/libnfsidmap.m4 -@@ -3,7 +3,7 @@ dnl - AC_DEFUN([AC_LIBNFSIDMAP], [ - - dnl Check for libnfsidmap, but do not add -lnfsidmap to LIBS -- AC_CHECK_LIB([nfsidmap], [nfs4_init_name_mapping], [libnfsidmap=1], -+ AC_CHECK_LIB([nfsidmap], [nfs4_init_name_mapping], [LIBNFSIDMAP=-lnfsidmap], - [AC_MSG_ERROR([libnfsidmap not found.])]) - - AC_CHECK_HEADERS([nfsidmap.h], , -@@ -14,7 +14,10 @@ AC_DEFUN([AC_LIBNFSIDMAP], [ - [AC_DEFINE([HAVE_NFS4_SET_DEBUG], 1, - [Define to 1 if you have the `nfs4_set_debug' function.])]) - -- dnl only enable nfsidmap when libnfsidmap supports it -- AC_CHECK_LIB([nfsidmap], [nfs4_owner_to_uid]) -+ dnl nfs4_owner_to_uid() doesn't appear in all versions of libnfsidmap -+ dnl We just need this test to set $ac_cv_lib_nfsidmap_nfs4_owner_to_uid -+ AC_CHECK_LIB([nfsidmap], [nfs4_owner_to_uid], [:]) -+ -+ AC_SUBST(LIBNFSIDMAP) - - ])dnl -diff --git a/aclocal/libsqlite3.m4 b/aclocal/libsqlite3.m4 -new file mode 100644 -index 0000000..73d1e46 ---- /dev/null -+++ b/aclocal/libsqlite3.m4 -@@ -0,0 +1,33 @@ -+dnl Checks for matching sqlite3 header and library, and -+dnl sufficient sqlite3 version. -+dnl -+AC_DEFUN([AC_SQLITE3_VERS], [ -+ AC_CHECK_HEADERS([sqlite3.h], ,) -+ -+ dnl look for the library; do not add to LIBS if found -+ AC_CHECK_LIB([sqlite3], [sqlite3_libversion_number], [LIBSQLITE=-lsqlite3], ,) -+ AC_SUBST(LIBSQLITE) -+ -+ AC_MSG_CHECKING(for suitable sqlite3 version) -+ -+ AC_CACHE_VAL([libsqlite3_cv_is_recent], -+ [ -+ saved_LIBS="$LIBS" -+ LIBS=-lsqlite3 -+ AC_TRY_RUN([ -+ #include -+ #include -+ int main() -+ { -+ int vers = sqlite3_libversion_number(); -+ -+ return vers != SQLITE_VERSION_NUMBER || -+ vers < 3003000; -+ } -+ ], [libsqlite3_cv_is_recent=yes], [libsqlite3_cv_is_recent=no], -+ [libsqlite3_cv_is_recent=unknown]) -+ LIBS="$saved_LIBS"]) -+ -+ AC_MSG_RESULT($libsqlite3_cv_is_recent) -+ AM_CONDITIONAL(CONFIG_SQLITE3, [test "$libsqlite3_cv_is_recent" = "yes"]) -+])dnl -diff --git a/aclocal/libtirpc.m4 b/aclocal/libtirpc.m4 -index 9f0fde0..19b8361 100644 ---- a/aclocal/libtirpc.m4 -+++ b/aclocal/libtirpc.m4 -@@ -13,8 +13,8 @@ AC_DEFUN([AC_LIBTIRPC], [ - - if test "$enable_tirpc" != "no"; then - -- dnl look for the library; add to LIBS if found -- AC_CHECK_LIB([tirpc], [clnt_tli_create], , -+ dnl look for the library -+ AC_CHECK_LIB([tirpc], [clnt_tli_create], [:], - [if test "$enable_tirpc" = "yes"; then - AC_MSG_ERROR([libtirpc not found.]) - else -@@ -37,4 +37,15 @@ AC_DEFUN([AC_LIBTIRPC], [ - - fi - -+ dnl now set $LIBTIRPC accordingly -+ if test "$enable_tirpc" != "no"; then -+ AC_DEFINE([HAVE_LIBTIRPC], 1, -+ [Define to 1 if you have and wish to use libtirpc.]) -+ LIBTIRPC="-ltirpc" -+ else -+ LIBTIRPC="" -+ fi -+ -+ AC_SUBST(LIBTIRPC) -+ - ])dnl -diff --git a/configure.ac b/configure.ac -index 80fb39d..20c452b 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -24,9 +24,8 @@ AC_ARG_WITH(statedir, - statedir=/var/lib/nfs) - AC_SUBST(statedir) - AC_ARG_WITH(statdpath, -- [AC_HELP_STRING([--with-statdpath=/foo @<:@default=/var/lib/nfs@:>@], -- [define statd's state dir as /foo instead of the NFS statedir] -- )], -+ [AC_HELP_STRING([--with-statdpath=/foo], -+ [define the statd state dir as /foo instead of the NFS statedir @<:@default=/var/lib/nfs@:>@])], - statdpath=$withval, - statdpath=$statedir - ) -@@ -186,6 +185,12 @@ else - AM_CONDITIONAL(MOUNT_CONFIG, [test "$enable_mount" = "yes"]) - fi - -+AC_ARG_ENABLE(nfsdcld, -+ [AC_HELP_STRING([--enable-nfsdcld], -+ [Create nfsdcld NFSv4 clientid tracking daemon. @<:@default=no@:>@])], -+ enable_nfsdcld=$enableval, -+ enable_nfsdcld="no") -+ - dnl Check for TI-RPC library and headers - AC_LIBTIRPC - -@@ -249,6 +254,8 @@ AC_CHECK_FUNC([getservbyname], , - - AC_CHECK_LIB([crypt], [crypt], [LIBCRYPT="-lcrypt"]) - -+AC_CHECK_LIB([dl], [dlclose], [LIBDL="-ldl"]) -+ - if test "$enable_nfsv4" = yes; then - dnl check for libevent libraries and headers - AC_LIBEVENT -@@ -259,12 +266,32 @@ if test "$enable_nfsv4" = yes; then - dnl check for the keyutils libraries and headers - AC_KEYUTILS - -+ dnl Check for sqlite3 -+ AC_SQLITE3_VERS -+ -+ if test "$enable_nfsdcld" = "yes"; then -+ AC_CHECK_HEADERS([libgen.h sys/inotify.h], , -+ AC_MSG_ERROR([Cannot find header needed for nfsdcld])) -+ -+ if test "$libsqlite3_cv_is_recent" != "yes" ; then -+ AC_MSG_ERROR([nfsdcld requires sqlite3]) -+ fi -+ fi -+ -+ AM_CONDITIONAL(CONFIG_NFSDCLD, [test "$enable_nfsdcld" = "yes" ]) -+ - dnl librpcsecgss already has a dependency on libgssapi, - dnl but we need to make sure we get the right version - if test "$enable_gss" = yes; then - AC_RPCSEC_VERSION - fi - fi -+ -+if test "$enable_nfsv41" = yes; then -+ AC_CHECK_LIB([devmapper], [dm_task_create], [LIBDEVMAPPER="-ldevmapper"], AC_MSG_ERROR([libdevmapper needed])) -+ AC_CHECK_HEADER(libdevmapper.h, , AC_MSG_ERROR([Cannot find devmapper header file libdevmapper.h])) -+fi -+ - dnl enable nfsidmap when its support by libnfsidmap - AM_CONDITIONAL(CONFIG_NFSIDMAP, [test "$ac_cv_header_keyutils_h$ac_cv_lib_nfsidmap_nfs4_owner_to_uid" = "yesyes"]) - -@@ -293,6 +320,7 @@ AC_SUBST(LIBSOCKET) - AC_SUBST(LIBCRYPT) - AC_SUBST(LIBBSD) - AC_SUBST(LIBBLKID) -+AC_SUBST(LIBDL) - - if test "$enable_libmount" != no; then - AC_CHECK_LIB(mount, mnt_context_do_mount, [LIBMOUNT="-lmount"], AC_MSG_ERROR([libmount needed])) -@@ -308,9 +336,6 @@ if test "$enable_gss" = yes; then - dnl 'gss' also depends on nfsidmap.h - at least for svcgssd_proc.c - AC_LIBNFSIDMAP - -- AC_CHECK_HEADERS([spkm3.h], , -- [AC_MSG_WARN([Could not locate SPKM3 header; will not have SPKM3 support])]) -- - dnl Check for Kerberos V5 - AC_KERBEROS_V5 - -@@ -330,7 +355,7 @@ AC_CHECK_HEADERS([arpa/inet.h fcntl.h libintl.h limits.h \ - stdlib.h string.h sys/file.h sys/ioctl.h sys/mount.h \ - sys/param.h sys/socket.h sys/time.h sys/vfs.h \ - syslog.h unistd.h com_err.h et/com_err.h \ -- ifaddrs.h]) -+ ifaddrs.h nfs-plugin.h]) - - dnl ************************************************************* - dnl Checks for typedefs, structures, and compiler characteristics -@@ -452,6 +477,7 @@ AC_CONFIG_FILES([ - tools/nfs-iostat/Makefile - utils/Makefile - utils/blkmapd/Makefile -+ utils/nfsdcld/Makefile - utils/exportfs/Makefile - utils/gssd/Makefile - utils/idmapd/Makefile -@@ -462,6 +488,7 @@ AC_CONFIG_FILES([ - utils/nfsidmap/Makefile - utils/showmount/Makefile - utils/statd/Makefile -+ utils/osd_login/Makefile - tests/Makefile - tests/nsm_client/Makefile]) - AC_OUTPUT -diff --git a/support/include/cld.h b/support/include/cld.h -new file mode 100644 -index 0000000..f14a9ab ---- /dev/null -+++ b/support/include/cld.h -@@ -0,0 +1,56 @@ -+/* -+ * Upcall description for nfsdcld communication -+ * -+ * Copyright (c) 2012 Red Hat, Inc. -+ * Author(s): Jeff Layton -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+#ifndef _NFSD_CLD_H -+#define _NFSD_CLD_H -+ -+/* latest upcall version available */ -+#define CLD_UPCALL_VERSION 1 -+ -+/* defined by RFC3530 */ -+#define NFS4_OPAQUE_LIMIT 1024 -+ -+enum cld_command { -+ Cld_Create, /* create a record for this cm_id */ -+ Cld_Remove, /* remove record of this cm_id */ -+ Cld_Check, /* is this cm_id allowed? */ -+ Cld_GraceDone, /* grace period is complete */ -+}; -+ -+/* representation of long-form NFSv4 client ID */ -+struct cld_name { -+ uint16_t cn_len; /* length of cm_id */ -+ unsigned char cn_id[NFS4_OPAQUE_LIMIT]; /* client-provided */ -+} __attribute__((packed)); -+ -+/* message struct for communication with userspace */ -+struct cld_msg { -+ uint8_t cm_vers; /* upcall version */ -+ uint8_t cm_cmd; /* upcall command */ -+ int16_t cm_status; /* return code */ -+ uint32_t cm_xid; /* transaction id */ -+ union { -+ int64_t cm_gracetime; /* grace period start time */ -+ struct cld_name cm_name; -+ } __attribute__((packed)) cm_u; -+} __attribute__((packed)); -+ -+#endif /* !_NFSD_CLD_H */ -diff --git a/support/include/exportfs.h b/support/include/exportfs.h -index 01e87dd..99916e5 100644 ---- a/support/include/exportfs.h -+++ b/support/include/exportfs.h -@@ -32,6 +32,10 @@ enum { - FSLOC_STUB - }; - -+#ifndef EXP_LOCKFILE -+#define EXP_LOCKFILE "/var/lib/nfs/export-lock" -+#endif -+ - typedef struct mclient { - struct mclient * m_next; - char * m_hostname; -diff --git a/support/include/nfs/debug.h b/support/include/nfs/debug.h -index d391e91..dbec5ba 100644 ---- a/support/include/nfs/debug.h -+++ b/support/include/nfs/debug.h -@@ -76,6 +76,9 @@ enum { - #define NFSDBG_CALLBACK 0x0100 - #define NFSDBG_CLIENT 0x0200 - #define NFSDBG_MOUNT 0x0400 -+#define NFSDBG_FSCACHE 0x0800 -+#define NFSDBG_PNFS 0x1000 -+#define NFSDBG_PNFS_LD 0x2000 - #define NFSDBG_ALL 0xFFFF - - #endif /* _NFS_DEBUG_H */ -diff --git a/support/include/pseudoflavors.h b/support/include/pseudoflavors.h -index c21087b..deb052b 100644 ---- a/support/include/pseudoflavors.h -+++ b/support/include/pseudoflavors.h -@@ -4,9 +4,6 @@ - #define RPC_AUTH_GSS_LKEY 390006 - #define RPC_AUTH_GSS_LKEYI 390007 - #define RPC_AUTH_GSS_LKEYP 390008 --#define RPC_AUTH_GSS_SPKM 390009 --#define RPC_AUTH_GSS_SPKMI 390010 --#define RPC_AUTH_GSS_SPKMP 390011 - - struct flav_info { - char *flavour; -diff --git a/support/nfs/conffile.c b/support/nfs/conffile.c -index fa0dc6b..5015e94 100644 ---- a/support/nfs/conffile.c -+++ b/support/nfs/conffile.c -@@ -49,6 +49,8 @@ - #include "conffile.h" - #include "xlog.h" - -+#pragma GCC visibility push(hidden) -+ - static void conf_load_defaults(void); - static int conf_set(int , char *, char *, char *, - char *, int , int ); -@@ -211,7 +213,7 @@ static void - conf_parse_line(int trans, char *line, size_t sz) - { - char *val, *ptr; -- size_t i; -+ size_t i, valsize; - size_t j; - static char *section = 0; - static char *arg = 0; -@@ -256,13 +258,14 @@ conf_parse_line(int trans, char *line, size_t sz) - val++, j++; - if (*val) - i = j; -- section = malloc(i); -+ section = malloc(i+1); - if (!section) { - xlog_warn("conf_parse_line: %d: malloc (%lu) failed", ln, - (unsigned long)i); - return; - } - strncpy(section, line, i); -+ section[i] = '\0'; - - if (arg) - free(arg); -@@ -297,23 +300,16 @@ conf_parse_line(int trans, char *line, size_t sz) - } - line[strcspn (line, " \t=")] = '\0'; - val = line + i + 1 + strspn (line + i + 1, " \t"); -+ valsize = 0; -+ while (val[valsize++]); - -- /* Skip trailing comments, if any */ -- for (j = 0; j < sz - (val - line); j++) { -- if (val[j] == '#' || val[j] == ';') { -+ /* Skip trailing spaces and comments */ -+ for (j = 0; j < valsize; j++) { -+ if (val[j] == '#' || val[j] == ';' || isspace(val[j])) { - val[j] = '\0'; - break; - } - } -- -- /* Skip trailing whitespace, if any */ -- for (j--; j > 0; j--) { -- if (isspace(val[j])) -- val[j] = '\0'; -- else -- break; -- } -- - /* XXX Perhaps should we not ignore errors? */ - conf_set(trans, section, arg, line, val, 0, 0); - return; -diff --git a/support/nfs/exports.c b/support/nfs/exports.c -index c96500f..84a2b08 100644 ---- a/support/nfs/exports.c -+++ b/support/nfs/exports.c -@@ -39,12 +39,6 @@ struct flav_info flav_map[] = { - { "krb5", RPC_AUTH_GSS_KRB5 }, - { "krb5i", RPC_AUTH_GSS_KRB5I }, - { "krb5p", RPC_AUTH_GSS_KRB5P }, -- { "lipkey", RPC_AUTH_GSS_LKEY }, -- { "lipkey-i", RPC_AUTH_GSS_LKEYI }, -- { "lipkey-p", RPC_AUTH_GSS_LKEYP }, -- { "spkm3", RPC_AUTH_GSS_SPKM }, -- { "spkm3i", RPC_AUTH_GSS_SPKMI }, -- { "spkm3p", RPC_AUTH_GSS_SPKMP }, - { "unix", AUTH_UNIX }, - { "sys", AUTH_SYS }, - { "null", AUTH_NULL }, -diff --git a/support/nfs/nfsctl.c b/support/nfs/nfsctl.c -index 89fa1a4..fec775f 100644 ---- a/support/nfs/nfsctl.c -+++ b/support/nfs/nfsctl.c -@@ -11,16 +11,22 @@ - #endif - - #include -+#include - #include - #include "nfslib.h" - - /* compatibility hack... */ --#ifndef __NR_nfsctl -+#if !defined(__NR_nfsctl) && defined(__NR_nfsservctl) - #define __NR_nfsctl __NR_nfsservctl - #endif - - int - nfsctl (int cmd, struct nfsctl_arg * argp, union nfsctl_res * resp) - { -+#ifdef __NR_nfsctl - return syscall (__NR_nfsctl, cmd, argp, resp); -+#else -+ errno = ENOSYS; -+ return -1; -+#endif - } -diff --git a/tools/rpcdebug/rpcdebug.c b/tools/rpcdebug/rpcdebug.c -index 275a491..444616d 100644 ---- a/tools/rpcdebug/rpcdebug.c -+++ b/tools/rpcdebug/rpcdebug.c -@@ -167,6 +167,9 @@ static struct flagmap { - FLAG(NFS, CALLBACK), - FLAG(NFS, CLIENT), - FLAG(NFS, MOUNT), -+ FLAG(NFS, FSCACHE), -+ FLAG(NFS, PNFS), -+ FLAG(NFS, PNFS_LD), - FLAG(NFS, ALL), - - /* nfsd */ -diff --git a/tools/rpcgen/Makefile.am b/tools/rpcgen/Makefile.am -index 51a2bfa..8a9ec89 100644 ---- a/tools/rpcgen/Makefile.am -+++ b/tools/rpcgen/Makefile.am -@@ -12,6 +12,7 @@ rpcgen_SOURCES = rpc_clntout.c rpc_cout.c rpc_hout.c rpc_main.c \ - rpcgen_CFLAGS=$(CFLAGS_FOR_BUILD) - rpcgen_CPPLAGS=$(CPPFLAGS_FOR_BUILD) - rpcgen_LDFLAGS=$(LDFLAGS_FOR_BUILD) -+rpcgen_LDADD=$(LIBTIRPC) - - MAINTAINERCLEANFILES = Makefile.in - -diff --git a/utils/Makefile.am b/utils/Makefile.am -index d074b85..09045dd 100644 ---- a/utils/Makefile.am -+++ b/utils/Makefile.am -@@ -21,6 +21,10 @@ if CONFIG_MOUNT - OPTDIRS += mount - endif - -+if CONFIG_NFSDCLD -+OPTDIRS += nfsdcld -+endif -+ - SUBDIRS = \ - exportfs \ - mountd \ -@@ -28,6 +32,7 @@ SUBDIRS = \ - nfsstat \ - showmount \ - statd \ -+ osd_login \ - $(OPTDIRS) - - MAINTAINERCLEANFILES = Makefile.in -diff --git a/utils/blkmapd/device-process.c b/utils/blkmapd/device-process.c -index 27ff374..652a7a8 100644 ---- a/utils/blkmapd/device-process.c -+++ b/utils/blkmapd/device-process.c -@@ -296,7 +296,7 @@ decode_blk_volume(uint32_t **pp, uint32_t *end, struct bl_volume *vols, int voln - off_t stripe_unit = vol->param.bv_stripe_unit; - /* Check limitations imposed by device-mapper */ - if ((stripe_unit & (stripe_unit - 1)) != 0 -- || stripe_unit < (off_t) (PAGE_SIZE >> 9)) -+ || stripe_unit < (off_t) (sysconf(_SC_PAGE_SIZE) >> 9)) - return -EIO; - BLK_READBUF(p, end, 4); - READ32(vol->bv_vol_n); -diff --git a/utils/exportfs/exportfs.c b/utils/exportfs/exportfs.c -index 7432a65..a3323d7 100644 ---- a/utils/exportfs/exportfs.c -+++ b/utils/exportfs/exportfs.c -@@ -16,6 +16,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -43,6 +44,41 @@ static void usage(const char *progname); - static void validate_export(nfs_export *exp); - static int matchhostname(const char *hostname1, const char *hostname2); - static void export_d_read(const char *dname); -+static void grab_lockfile(void); -+static void release_lockfile(void); -+ -+static const char *lockfile = EXP_LOCKFILE; -+static int _lockfd = -1; -+ -+/* -+ * If we aren't careful, changes made by exportfs can be lost -+ * when multiple exports process run at once: -+ * -+ * exportfs process 1 exportfs process 2 -+ * ------------------------------------------ -+ * reads etab version A reads etab version A -+ * adds new export B adds new export C -+ * writes A+B writes A+C -+ * -+ * The locking in support/export/xtab.c will prevent mountd from -+ * seeing a partially written version of etab, and will prevent -+ * the two writers above from writing simultaneously and -+ * corrupting etab, but to prevent problems like the above we -+ * need these additional lockfile() routines. -+ */ -+static void -+grab_lockfile() -+{ -+ _lockfd = open(lockfile, O_CREAT|O_RDWR, 0666); -+ if (_lockfd != -1) -+ lockf(_lockfd, F_LOCK, 0); -+} -+static void -+release_lockfile() -+{ -+ if (_lockfd != -1) -+ lockf(_lockfd, F_ULOCK, 0); -+} - - int - main(int argc, char **argv) -@@ -129,6 +165,13 @@ main(int argc, char **argv) - return 0; - } - } -+ -+ /* -+ * Serialize things as best we can -+ */ -+ grab_lockfile(); -+ atexit(release_lockfile); -+ - if (f_export && ! f_ignore) { - export_read(_PATH_EXPORTS); - export_d_read(_PATH_EXPORTS_D); -diff --git a/utils/exportfs/exportfs.man b/utils/exportfs/exportfs.man -index 364f247..8853486 100644 ---- a/utils/exportfs/exportfs.man -+++ b/utils/exportfs/exportfs.man -@@ -177,7 +177,7 @@ In this way - .B exportfs - can be used to modify the export options of an already exported directory. - .SS Unexporting Directories --The third synopsis shows how to unexported a currently exported directory. -+The third synopsis shows how to unexport a currently exported directory. - When using - .BR "exportfs -ua" , - all entries listed in -diff --git a/utils/exportfs/exports.man b/utils/exportfs/exports.man -index 54adfeb..bc1de73 100644 ---- a/utils/exportfs/exports.man -+++ b/utils/exportfs/exports.man -@@ -293,24 +293,6 @@ be explicitly requested with either of the synonymous - .IR auth_nlm , - or - .IR secure_locks . --.TP --.IR no_acl --On some specially patched kernels, and when exporting filesystems that --support ACLs, this option tells --.B nfsd --not to reveal ACLs to clients, so --they will see only a subset of actual permissions on the given file --system. This option is safe for filesystems used by NFSv2 clients and --old NFSv3 clients that perform access decisions locally. Current --NFSv3 clients use the ACCESS RPC to perform all access decisions on --the server. Note that the --.I no_acl --option only has effect on kernels specially patched to support it, and --when exporting filesystems with ACL support. The default is to export --with ACL support (i.e. by default, --.I no_acl --is off). -- - .\".TP - .\".I noaccess - .\"This makes everything below the directory inaccessible for the named -diff --git a/utils/exportfs/nfsd.man b/utils/exportfs/nfsd.man -index 7365a1b..47b73be 100644 ---- a/utils/exportfs/nfsd.man -+++ b/utils/exportfs/nfsd.man -@@ -12,7 +12,7 @@ nfsd \- special filesystem for controlling Linux NFS server - .SH DESCRIPTION - The - .B nfsd --filesytem is a special filesystem which provides access to the Linux -+filesystem is a special filesystem which provides access to the Linux - NFS server. The filesystem consists of a single directory which - contains a number of files. These files are actually gateways into - the NFS server. Writing to them can affect the server. Reading from -@@ -86,7 +86,7 @@ should be followed by a newline, with white-space separating the - fields, and octal quoting of special characters. - - On writing this, the program will be able to read back a filehandle --for that path as exported to the given client. The filehandles length -+for that path as exported to the given client. The filehandle's length - will be at most the number of bytes given. - - The filehandle will be represented in hex with a leading '\ex'. -@@ -165,7 +165,7 @@ file. The user-space program might then write - .ti +5 - nfsd 127.0.0.1 1057206953 localhost - .br --to indicate that 127.0.0.1 should map to localhost, atleast for now. -+to indicate that 127.0.0.1 should map to localhost, at least for now. - - If the program uses select(2) or poll(2) to discover if it can read - from the -diff --git a/utils/gssd/Makefile.am b/utils/gssd/Makefile.am -index d7888ad..2365704 100644 ---- a/utils/gssd/Makefile.am -+++ b/utils/gssd/Makefile.am -@@ -17,7 +17,6 @@ COMMON_SRCS = \ - context_mit.c \ - context_heimdal.c \ - context_lucid.c \ -- context_spkm3.c \ - gss_util.c \ - gss_oids.c \ - err_util.c \ -@@ -40,7 +39,7 @@ gssd_SOURCES = \ - - gssd_LDADD = ../../support/nfs/libnfs.a \ - $(RPCSECGSS_LIBS) $(GSSGLUE_LIBS) $(KRBLIBS) --gssd_LDFLAGS = $(KRBLDFLAGS) -+gssd_LDFLAGS = $(KRBLDFLAGS) $(LIBTIRPC) - - gssd_CFLAGS = $(AM_CFLAGS) $(CFLAGS) \ - $(RPCSECGSS_CFLAGS) $(GSSGLUE_CFLAGS) $(KRBCFLAGS) -@@ -58,8 +57,8 @@ svcgssd_SOURCES = \ - - svcgssd_LDADD = \ - ../../support/nfs/libnfs.a \ -- $(RPCSECGSS_LIBS) $(GSSGLUE_LIBS) -lnfsidmap \ -- $(KRBLIBS) -+ $(RPCSECGSS_LIBS) $(GSSGLUE_LIBS) $(LIBNFSIDMAP) \ -+ $(KRBLIBS) $(LIBTIRPC) - - svcgssd_LDFLAGS = $(KRBLDFLAGS) - -diff --git a/utils/gssd/context.c b/utils/gssd/context.c -index 1e50bbf..fee7da2 100644 ---- a/utils/gssd/context.c -+++ b/utils/gssd/context.c -@@ -51,10 +51,6 @@ serialize_context_for_kernel(gss_ctx_id_t ctx, - { - if (g_OID_equal(&krb5oid, mech)) - return serialize_krb5_ctx(ctx, buf, endtime); --#ifdef HAVE_SPKM3_H -- else if (g_OID_equal(&spkm3oid, mech)) -- return serialize_spkm3_ctx(ctx, buf, endtime); --#endif - else { - printerr(0, "ERROR: attempting to serialize context with " - "unknown/unsupported mechanism oid\n"); -diff --git a/utils/gssd/context.h b/utils/gssd/context.h -index c9cb0bd..0e437f4 100644 ---- a/utils/gssd/context.h -+++ b/utils/gssd/context.h -@@ -43,8 +43,6 @@ - - int serialize_context_for_kernel(gss_ctx_id_t ctx, gss_buffer_desc *buf, - gss_OID mech, int32_t *endtime); --int serialize_spkm3_ctx(gss_ctx_id_t ctx, gss_buffer_desc *buf, -- int32_t *endtime); - int serialize_krb5_ctx(gss_ctx_id_t ctx, gss_buffer_desc *buf, - int32_t *endtime); - -diff --git a/utils/gssd/context_lucid.c b/utils/gssd/context_lucid.c -index 3e695ab..64146d7 100644 ---- a/utils/gssd/context_lucid.c -+++ b/utils/gssd/context_lucid.c -@@ -80,6 +80,7 @@ prepare_krb5_rfc1964_buffer(gss_krb5_lucid_context_v1_t *lctx, - uint32_t i; - char *skd, *dkd; - gss_buffer_desc fakeoid; -+ int err; - - /* - * The new Kerberos interface to get the gss context -@@ -138,11 +139,10 @@ prepare_krb5_rfc1964_buffer(gss_krb5_lucid_context_v1_t *lctx, - dkd = (char *) enc_key.data; - for (i = 0; i < enc_key.length; i++) - dkd[i] = skd[i] ^ 0xf0; -- if (write_lucid_keyblock(&p, end, &enc_key)) { -- free(enc_key.data); -- goto out_err; -- } -+ err = write_lucid_keyblock(&p, end, &enc_key); - free(enc_key.data); -+ if (err) -+ goto out_err; - - if (write_lucid_keyblock(&p, end, &lctx->rfc1964_kd.ctx_key)) - goto out_err; -@@ -153,7 +153,6 @@ out_err: - printerr(0, "ERROR: failed serializing krb5 context for kernel\n"); - if (buf->value) free(buf->value); - buf->length = 0; -- if (enc_key.data) free(enc_key.data); - return -1; - } - -diff --git a/utils/gssd/context_spkm3.c b/utils/gssd/context_spkm3.c -deleted file mode 100644 -index b927475..0000000 ---- a/utils/gssd/context_spkm3.c -+++ /dev/null -@@ -1,184 +0,0 @@ --/* -- Copyright (c) 2004 The Regents of the University of Michigan. -- All rights reserved. -- -- Redistribution and use in source and binary forms, with or without -- modification, are permitted provided that the following conditions -- are met: -- -- 1. Redistributions of source code must retain the above copyright -- notice, this list of conditions and the following disclaimer. -- 2. Redistributions in binary form must reproduce the above copyright -- notice, this list of conditions and the following disclaimer in the -- documentation and/or other materials provided with the distribution. -- 3. Neither the name of the University nor the names of its -- contributors may be used to endorse or promote products derived -- from this software without specific prior written permission. -- -- THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED -- WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -- DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -- BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --*/ -- --#ifdef HAVE_CONFIG_H --#include --#endif /* HAVE_CONFIG_H */ -- --#include --#include --#include --#include --#include --#include --#include "gss_util.h" --#include "gss_oids.h" --#include "err_util.h" --#include "context.h" -- --#ifdef HAVE_SPKM3_H -- --#include -- --/* -- * Function: prepare_spkm3_ctx_buffer() -- * -- * Prepare spkm3 lucid context for the kernel -- * -- * buf->length should be: -- * -- * version 4 -- * ctx_id 4 + 12 -- * qop 4 -- * mech_used 4 + 7 -- * ret_fl 4 -- * req_fl 4 -- * share 4 + key_len -- * conf_alg 4 + oid_len -- * d_conf_key 4 + key_len -- * intg_alg 4 + oid_len -- * d_intg_key 4 + key_len -- * kyestb 4 + oid_len -- * owl alg 4 + oid_len --*/ --static int --prepare_spkm3_ctx_buffer(gss_spkm3_lucid_ctx_t *lctx, gss_buffer_desc *buf) --{ -- char *p, *end; -- unsigned int buf_size = 0; -- -- buf_size = sizeof(lctx->version) + -- lctx->ctx_id.length + sizeof(lctx->ctx_id.length) + -- sizeof(lctx->endtime) + -- sizeof(lctx->mech_used.length) + lctx->mech_used.length + -- sizeof(lctx->ret_flags) + -- sizeof(lctx->conf_alg.length) + lctx->conf_alg.length + -- sizeof(lctx->derived_conf_key.length) + -- lctx->derived_conf_key.length + -- sizeof(lctx->intg_alg.length) + lctx->intg_alg.length + -- sizeof(lctx->derived_integ_key.length) + -- lctx->derived_integ_key.length; -- -- if (!(buf->value = calloc(1, buf_size))) -- goto out_err; -- p = buf->value; -- end = buf->value + buf_size; -- -- if (WRITE_BYTES(&p, end, lctx->version)) -- goto out_err; -- printerr(2, "DEBUG: exporting version = %d\n", lctx->version); -- -- if (write_buffer(&p, end, &lctx->ctx_id)) -- goto out_err; -- printerr(2, "DEBUG: exporting ctx_id(%d)\n", lctx->ctx_id.length); -- -- if (WRITE_BYTES(&p, end, lctx->endtime)) -- goto out_err; -- printerr(2, "DEBUG: exporting endtime = %d\n", lctx->endtime); -- -- if (write_buffer(&p, end, &lctx->mech_used)) -- goto out_err; -- printerr(2, "DEBUG: exporting mech oid (%d)\n", lctx->mech_used.length); -- -- if (WRITE_BYTES(&p, end, lctx->ret_flags)) -- goto out_err; -- printerr(2, "DEBUG: exporting ret_flags = %d\n", lctx->ret_flags); -- -- if (write_buffer(&p, end, &lctx->conf_alg)) -- goto out_err; -- printerr(2, "DEBUG: exporting conf_alg oid (%d)\n", lctx->conf_alg.length); -- -- if (write_buffer(&p, end, &lctx->derived_conf_key)) -- goto out_err; -- printerr(2, "DEBUG: exporting conf key (%d)\n", lctx->derived_conf_key.length); -- -- if (write_buffer(&p, end, &lctx->intg_alg)) -- goto out_err; -- printerr(2, "DEBUG: exporting intg_alg oid (%d)\n", lctx->intg_alg.length); -- -- if (write_buffer(&p, end, &lctx->derived_integ_key)) -- goto out_err; -- printerr(2, "DEBUG: exporting intg key (%d)\n", lctx->derived_integ_key.length); -- -- buf->length = p - (char *)buf->value; -- return 0; --out_err: -- printerr(0, "ERROR: failed serializing spkm3 context for kernel\n"); -- if (buf->value) free(buf->value); -- buf->length = 0; -- -- return -1; --} -- --/* ANDROS: need to determine which fields of the spkm3_gss_ctx_id_desc_t -- * are needed in the kernel for get_mic, validate, wrap, unwrap, and destroy -- * and only export those fields to the kernel. -- */ --int --serialize_spkm3_ctx(gss_ctx_id_t ctx, gss_buffer_desc *buf, int32_t *endtime) --{ -- OM_uint32 vers, ret, maj_stat, min_stat; -- void *ret_ctx = 0; -- gss_spkm3_lucid_ctx_t *lctx; -- -- printerr(1, "serialize_spkm3_ctx called\n"); -- -- printerr(2, "DEBUG: serialize_spkm3_ctx: lucid version!\n"); -- maj_stat = gss_export_lucid_sec_context(&min_stat, &ctx, 1, &ret_ctx); -- if (maj_stat != GSS_S_COMPLETE) -- goto out_err; -- -- lctx = (gss_spkm3_lucid_ctx_t *)ret_ctx; -- -- vers = lctx->version; -- if (vers != 1) { -- printerr(0, "ERROR: unsupported spkm3 context version %d\n", -- vers); -- goto out_err; -- } -- ret = prepare_spkm3_ctx_buffer(lctx, buf); -- -- if (endtime) -- *endtime = lctx->endtime; -- -- maj_stat = gss_free_lucid_sec_context(&min_stat, ctx, ret_ctx); -- -- if (maj_stat != GSS_S_COMPLETE) -- printerr(0, "WARN: failed to free lucid sec context\n"); -- if (ret) -- goto out_err; -- printerr(2, "DEBUG: serialize_spkm3_ctx: success\n"); -- return 0; -- --out_err: -- printerr(2, "DEBUG: serialize_spkm3_ctx: failed\n"); -- return -1; --} --#endif /* HAVE_SPKM3_H */ -diff --git a/utils/gssd/gss_oids.c b/utils/gssd/gss_oids.c -index a59c4a6..4362de2 100644 ---- a/utils/gssd/gss_oids.c -+++ b/utils/gssd/gss_oids.c -@@ -38,6 +38,3 @@ - /* from kerberos source, gssapi_krb5.c */ - gss_OID_desc krb5oid = - {9, "\052\206\110\206\367\022\001\002\002"}; -- --gss_OID_desc spkm3oid = -- {7, "\053\006\001\005\005\001\003"}; -diff --git a/utils/gssd/gss_oids.h b/utils/gssd/gss_oids.h -index 8b0a352..fde8532 100644 ---- a/utils/gssd/gss_oids.h -+++ b/utils/gssd/gss_oids.h -@@ -34,7 +34,6 @@ - #include - - extern gss_OID_desc krb5oid; --extern gss_OID_desc spkm3oid; - - #ifndef g_OID_equal - #define g_OID_equal(o1,o2) \ -diff --git a/utils/gssd/gssd.c b/utils/gssd/gssd.c -index ccadb07..7825255 100644 ---- a/utils/gssd/gssd.c -+++ b/utils/gssd/gssd.c -@@ -57,7 +57,7 @@ - - char pipefs_dir[PATH_MAX] = GSSD_PIPEFS_DIR; - char keytabfile[PATH_MAX] = GSSD_DEFAULT_KEYTAB_FILE; --char ccachedir[PATH_MAX] = GSSD_DEFAULT_CRED_DIR; -+char ccachedir[PATH_MAX] = GSSD_DEFAULT_CRED_DIR ":" GSSD_USER_CRED_DIR; - char *ccachesearch[GSSD_MAX_CCACHE_SEARCH + 1]; - int use_memcache = 0; - int root_uses_machine_creds = 1; -@@ -85,7 +85,7 @@ sig_hup(int signal) - static void - usage(char *progname) - { -- fprintf(stderr, "usage: %s [-f] [-M] [-n] [-v] [-r] [-p pipefsdir] [-k keytab] [-d ccachedir] [-t timeout] [-R preferred realm]\n", -+ fprintf(stderr, "usage: %s [-f] [-l] [-M] [-n] [-v] [-r] [-p pipefsdir] [-k keytab] [-d ccachedir] [-t timeout] [-R preferred realm]\n", - progname); - exit(1); - } -@@ -102,7 +102,7 @@ main(int argc, char *argv[]) - char *progname; - - memset(ccachesearch, 0, sizeof(ccachesearch)); -- while ((opt = getopt(argc, argv, "fvrmnMp:k:d:t:R:")) != -1) { -+ while ((opt = getopt(argc, argv, "fvrlmnMp:k:d:t:R")) != -1) { - switch (opt) { - case 'f': - fg = 1; -@@ -143,6 +143,13 @@ main(int argc, char *argv[]) - case 'R': - preferred_realm = strdup(optarg); - break; -+ case 'l': -+#ifdef HAVE_SET_ALLOWABLE_ENCTYPES -+ limit_to_legacy_enctypes = 1; -+#else -+ errx(1, "Setting encryption type not support by Kerberos libraries."); -+#endif -+ break; - default: - usage(argv[0]); - break; -diff --git a/utils/gssd/gssd.h b/utils/gssd/gssd.h -index b1b5793..28a8206 100644 ---- a/utils/gssd/gssd.h -+++ b/utils/gssd/gssd.h -@@ -45,6 +45,7 @@ - #define DNOTIFY_SIGNAL (SIGRTMIN + 3) - - #define GSSD_DEFAULT_CRED_DIR "/tmp" -+#define GSSD_USER_CRED_DIR "/run/user" - #define GSSD_DEFAULT_CRED_PREFIX "krb5cc_" - #define GSSD_DEFAULT_MACHINE_CRED_SUFFIX "machine" - #define GSSD_DEFAULT_KEYTAB_FILE "/etc/krb5.keytab" -@@ -55,7 +56,7 @@ - /* - * The gss mechanisms that we can handle - */ --enum {AUTHTYPE_KRB5, AUTHTYPE_SPKM3, AUTHTYPE_LIPKEY}; -+enum {AUTHTYPE_KRB5, AUTHTYPE_LIPKEY}; - - - -@@ -80,8 +81,6 @@ struct clnt_info { - char *protocol; - int krb5_fd; - int krb5_poll_index; -- int spkm3_fd; -- int spkm3_poll_index; - int gssd_fd; - int gssd_poll_index; - struct sockaddr_storage addr; -@@ -98,7 +97,6 @@ struct topdirs_info { - void init_client_list(void); - int update_client_list(void); - void handle_krb5_upcall(struct clnt_info *clp); --void handle_spkm3_upcall(struct clnt_info *clp); - void handle_gssd_upcall(struct clnt_info *clp); - void gssd_run(void); - -diff --git a/utils/gssd/gssd.man b/utils/gssd/gssd.man -index 073379d..d8138fa 100644 ---- a/utils/gssd/gssd.man -+++ b/utils/gssd/gssd.man -@@ -6,7 +6,7 @@ - .SH NAME - rpc.gssd \- rpcsec_gss daemon - .SH SYNOPSIS --.B "rpc.gssd [-f] [-n] [-k keytab] [-p pipefsdir] [-v] [-r] [-d ccachedir]" -+.B "rpc.gssd [-f] [-n] [-k keytab] [-l] [-p pipefsdir] [-v] [-r] [-d ccachedir]" - .SH DESCRIPTION - The rpcsec_gss protocol gives a means of using the gss-api generic security - api to provide security for protocols using rpc (in particular, nfs). Before -@@ -70,6 +70,30 @@ for "machine credentials" is now: - If this search order does not use the correct key then provide a - keytab file that contains only correct keys. - .TP -+.B -l -+Tells -+.B rpc.gssd -+to limit session keys to Single DES even if the kernel supports stronger -+encryption types. Service ticket encryption is still governed by what -+the KDC believes the target server supports. This way the client can -+access a server that has strong keys in its keytab for ticket decryption -+but whose kernel only supports Single DES. -+.IP -+The alternative is to put only Single DES keys in the server's keytab -+and limit encryption types for its principal to Single DES on the KDC -+which will cause service tickets for this server to be encrypted using -+only Single DES and (as a side-effect) contain only Single DES session -+keys. -+.IP -+This legacy behaviour is only required for older servers -+(pre nfs-utils-1.2.4). If the server has a recent kernel, Kerberos -+implementation and nfs-utils it will work just fine with stronger -+encryption. -+.IP -+.B Note: -+This option is only available with Kerberos libraries that -+support setable encryption types. -+.TP - .B -p path - Tells - .B rpc.gssd -diff --git a/utils/gssd/gssd_main_loop.c b/utils/gssd/gssd_main_loop.c -index b06c223..cec09ea 100644 ---- a/utils/gssd/gssd_main_loop.c -+++ b/utils/gssd/gssd_main_loop.c -@@ -98,17 +98,6 @@ scan_poll_results(int ret) - if (!ret) - break; - } -- i = clp->spkm3_poll_index; -- if (i >= 0 && pollarray[i].revents) { -- if (pollarray[i].revents & POLLHUP) -- dir_changed = 1; -- if (pollarray[i].revents & POLLIN) -- handle_spkm3_upcall(clp); -- pollarray[clp->spkm3_poll_index].revents = 0; -- ret--; -- if (!ret) -- break; -- } - } - }; - -diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c -index 41328c9..aa39435 100644 ---- a/utils/gssd/gssd_proc.c -+++ b/utils/gssd/gssd_proc.c -@@ -299,15 +299,11 @@ destroy_client(struct clnt_info *clp) - if (clp->krb5_poll_index != -1) - memset(&pollarray[clp->krb5_poll_index], 0, - sizeof(struct pollfd)); -- if (clp->spkm3_poll_index != -1) -- memset(&pollarray[clp->spkm3_poll_index], 0, -- sizeof(struct pollfd)); - if (clp->gssd_poll_index != -1) - memset(&pollarray[clp->gssd_poll_index], 0, - sizeof(struct pollfd)); - if (clp->dir_fd != -1) close(clp->dir_fd); - if (clp->krb5_fd != -1) close(clp->krb5_fd); -- if (clp->spkm3_fd != -1) close(clp->spkm3_fd); - if (clp->gssd_fd != -1) close(clp->gssd_fd); - free(clp->dirname); - free(clp->servicename); -@@ -327,10 +323,8 @@ insert_new_clnt(void) - goto out; - } - clp->krb5_poll_index = -1; -- clp->spkm3_poll_index = -1; - clp->gssd_poll_index = -1; - clp->krb5_fd = -1; -- clp->spkm3_fd = -1; - clp->gssd_fd = -1; - clp->dir_fd = -1; - -@@ -355,30 +349,22 @@ process_clnt_dir_files(struct clnt_info * clp) - snprintf(name, sizeof(name), "%s/krb5", clp->dirname); - clp->krb5_fd = open(name, O_RDWR); - } -- if (clp->spkm3_fd == -1) { -- snprintf(name, sizeof(name), "%s/spkm3", clp->dirname); -- clp->spkm3_fd = open(name, O_RDWR); -- } - - /* If we opened a gss-specific pipe, let's try opening - * the new upcall pipe again. If we succeed, close - * gss-specific pipe(s). - */ -- if (clp->krb5_fd != -1 || clp->spkm3_fd != -1) { -+ if (clp->krb5_fd != -1) { - clp->gssd_fd = open(gname, O_RDWR); - if (clp->gssd_fd != -1) { - if (clp->krb5_fd != -1) - close(clp->krb5_fd); - clp->krb5_fd = -1; -- if (clp->spkm3_fd != -1) -- close(clp->spkm3_fd); -- clp->spkm3_fd = -1; - } - } - } - -- if ((clp->krb5_fd == -1) && (clp->spkm3_fd == -1) && -- (clp->gssd_fd == -1)) -+ if ((clp->krb5_fd == -1) && (clp->gssd_fd == -1)) - return -1; - snprintf(info_file_name, sizeof(info_file_name), "%s/info", - clp->dirname); -@@ -431,15 +417,6 @@ insert_clnt_poll(struct clnt_info *clp) - pollarray[clp->krb5_poll_index].events |= POLLIN; - } - -- if ((clp->spkm3_fd != -1) && (clp->spkm3_poll_index == -1)) { -- if (get_poll_index(&clp->spkm3_poll_index)) { -- printerr(0, "ERROR: Too many spkm3 clients\n"); -- return -1; -- } -- pollarray[clp->spkm3_poll_index].fd = clp->spkm3_fd; -- pollarray[clp->spkm3_poll_index].events |= POLLIN; -- } -- - return 0; - } - -@@ -839,13 +816,6 @@ int create_auth_rpc_client(struct clnt_info *clp, - sec.mech = (gss_OID)&krb5oid; - sec.req_flags = GSS_C_MUTUAL_FLAG; - } -- else if (authtype == AUTHTYPE_SPKM3) { -- sec.mech = (gss_OID)&spkm3oid; -- /* XXX sec.req_flags = GSS_C_ANON_FLAG; -- * Need a way to switch.... -- */ -- sec.req_flags = GSS_C_MUTUAL_FLAG; -- } - else { - printerr(0, "ERROR: Invalid authentication type (%d) " - "in create_auth_rpc_client\n", authtype); -@@ -919,9 +889,8 @@ int create_auth_rpc_client(struct clnt_info *clp, - auth = authgss_create_default(rpc_clnt, clp->servicename, &sec); - if (!auth) { - /* Our caller should print appropriate message */ -- printerr(2, "WARNING: Failed to create %s context for " -+ printerr(2, "WARNING: Failed to create krb5 context for " - "user with uid %d for server %s\n", -- (authtype == AUTHTYPE_KRB5 ? "krb5":"spkm3"), - uid, clp->servername); - goto out_fail; - } -@@ -949,6 +918,23 @@ int create_auth_rpc_client(struct clnt_info *clp, - goto out; - } - -+static char * -+user_cachedir(char *dirname, uid_t uid) -+{ -+ struct passwd *pw; -+ char *ptr; -+ -+ if ((pw = getpwuid(uid)) == NULL) { -+ printerr(0, "user_cachedir: Failed to find '%d' uid" -+ " for cache directory\n"); -+ return NULL; -+ } -+ ptr = malloc(strlen(dirname)+strlen(pw->pw_name)+2); -+ if (ptr) -+ sprintf(ptr, "%s/%s", dirname, pw->pw_name); -+ -+ return ptr; -+} - /* - * this code uses the userland rpcsec gss library to create a krb5 - * context on behalf of the kernel -@@ -963,7 +949,7 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname, - gss_buffer_desc token; - char **credlist = NULL; - char **ccname; -- char **dirname; -+ char **dirname, *dir, *userdir; - int create_resp = -1; - int err, downcall_err = -EACCES; - -@@ -1006,7 +992,22 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname, - service == NULL)) { - /* Tell krb5 gss which credentials cache to use */ - for (dirname = ccachesearch; *dirname != NULL; dirname++) { -- err = gssd_setup_krb5_user_gss_ccache(uid, clp->servername, *dirname); -+ /* See if the user name is needed */ -+ if (strncmp(*dirname, GSSD_USER_CRED_DIR, -+ strlen(GSSD_USER_CRED_DIR)) == 0) { -+ userdir = user_cachedir(*dirname, uid); -+ if (userdir == NULL) -+ continue; -+ dir = userdir; -+ } else -+ dir = *dirname; -+ -+ err = gssd_setup_krb5_user_gss_ccache(uid, clp->servername, dir); -+ -+ if (userdir) { -+ free(userdir); -+ userdir = NULL; -+ } - if (err == -EKEYEXPIRED) - downcall_err = -EKEYEXPIRED; - else if (!err) -@@ -1103,59 +1104,6 @@ out_return_error: - goto out; - } - --/* -- * this code uses the userland rpcsec gss library to create an spkm3 -- * context on behalf of the kernel -- */ --static void --process_spkm3_upcall(struct clnt_info *clp, uid_t uid, int fd) --{ -- CLIENT *rpc_clnt = NULL; -- AUTH *auth = NULL; -- struct authgss_private_data pd; -- gss_buffer_desc token; -- -- printerr(2, "handling spkm3 upcall (%s)\n", clp->dirname); -- -- token.length = 0; -- token.value = NULL; -- -- if (create_auth_rpc_client(clp, &rpc_clnt, &auth, uid, AUTHTYPE_SPKM3)) { -- printerr(0, "WARNING: Failed to create spkm3 context for " -- "user with uid %d\n", uid); -- goto out_return_error; -- } -- -- if (!authgss_get_private_data(auth, &pd)) { -- printerr(0, "WARNING: Failed to obtain authentication " -- "data for user with uid %d for server %s\n", -- uid, clp->servername); -- goto out_return_error; -- } -- -- if (serialize_context_for_kernel(pd.pd_ctx, &token, &spkm3oid, NULL)) { -- printerr(0, "WARNING: Failed to serialize spkm3 context for " -- "user with uid %d for server\n", -- uid, clp->servername); -- goto out_return_error; -- } -- -- do_downcall(fd, uid, &pd, &token); -- --out: -- if (token.value) -- free(token.value); -- if (auth) -- AUTH_DESTROY(auth); -- if (rpc_clnt) -- clnt_destroy(rpc_clnt); -- return; -- --out_return_error: -- do_error_downcall(fd, uid, -1); -- goto out; --} -- - void - handle_krb5_upcall(struct clnt_info *clp) - { -@@ -1171,20 +1119,6 @@ handle_krb5_upcall(struct clnt_info *clp) - } - - void --handle_spkm3_upcall(struct clnt_info *clp) --{ -- uid_t uid; -- -- if (read(clp->spkm3_fd, &uid, sizeof(uid)) < (ssize_t)sizeof(uid)) { -- printerr(0, "WARNING: failed reading uid from spkm3 " -- "upcall pipe: %s\n", strerror(errno)); -- return; -- } -- -- return process_spkm3_upcall(clp, uid, clp->spkm3_fd); --} -- --void - handle_gssd_upcall(struct clnt_info *clp) - { - uid_t uid; -@@ -1292,8 +1226,6 @@ handle_gssd_upcall(struct clnt_info *clp) - - if (strcmp(mech, "krb5") == 0) - process_krb5_upcall(clp, uid, clp->gssd_fd, target, service); -- else if (strcmp(mech, "spkm3") == 0) -- process_spkm3_upcall(clp, uid, clp->gssd_fd); - else - printerr(0, "WARNING: handle_gssd_upcall: " - "received unknown gss mech '%s'\n", mech); -diff --git a/utils/gssd/krb5_util.c b/utils/gssd/krb5_util.c -index 4b13fa1..887d118 100644 ---- a/utils/gssd/krb5_util.c -+++ b/utils/gssd/krb5_util.c -@@ -129,6 +129,10 @@ - /* Global list of principals/cache file names for machine credentials */ - struct gssd_k5_kt_princ *gssd_k5_kt_princ_list = NULL; - -+#ifdef HAVE_SET_ALLOWABLE_ENCTYPES -+int limit_to_legacy_enctypes = 0; -+#endif -+ - /*==========================*/ - /*=== Internal routines ===*/ - /*==========================*/ -@@ -1342,7 +1346,7 @@ limit_krb5_enctypes(struct rpc_gss_sec *sec) - * If we failed for any reason to produce global - * list of supported enctypes, use local default here. - */ -- if (krb5_enctypes == NULL) -+ if (krb5_enctypes == NULL || limit_to_legacy_enctypes) - maj_stat = gss_set_allowable_enctypes(&min_stat, credh, - &krb5oid, num_enctypes, enctypes); - else -diff --git a/utils/gssd/krb5_util.h b/utils/gssd/krb5_util.h -index b42b91e..cd6e107 100644 ---- a/utils/gssd/krb5_util.h -+++ b/utils/gssd/krb5_util.h -@@ -36,6 +36,7 @@ char *gssd_k5_err_msg(krb5_context context, krb5_error_code code); - void gssd_k5_get_default_realm(char **def_realm); - - #ifdef HAVE_SET_ALLOWABLE_ENCTYPES -+extern int limit_to_legacy_enctypes; - int limit_krb5_enctypes(struct rpc_gss_sec *sec); - #endif - -diff --git a/utils/gssd/svcgssd_mech2file.c b/utils/gssd/svcgssd_mech2file.c -index 65de8d0..ecd908b 100644 ---- a/utils/gssd/svcgssd_mech2file.c -+++ b/utils/gssd/svcgssd_mech2file.c -@@ -53,8 +53,6 @@ struct mech2file { - - struct mech2file m2f[] = { - {{9, "\052\206\110\206\367\022\001\002\002"}, "krb5"}, -- {{7, "\053\006\001\005\005\001\003"}, "spkm3"}, -- {{7, "\053\006\001\005\005\001\009"}, "lipkey"}, - {{0,0},""}, - }; - -diff --git a/utils/gssd/svcgssd_proc.c b/utils/gssd/svcgssd_proc.c -index c714d99..0d4f78d 100644 ---- a/utils/gssd/svcgssd_proc.c -+++ b/utils/gssd/svcgssd_proc.c -@@ -369,12 +369,8 @@ get_hostbased_client_name(gss_name_t client_name, gss_OID mech, - if (g_OID_equal(&krb5oid, mech)) { - if (get_krb5_hostbased_name(&name, &cname) == 0) - *hostbased_name = cname; -- } -- -- /* No support for SPKM3, just print a warning (for now) */ -- if (g_OID_equal(&spkm3oid, mech)) { -- printerr(1, "WARNING: get_hostbased_client_name: " -- "no hostbased_name support for SPKM3\n"); -+ } else { -+ printerr(1, "WARNING: unknown/unsupport mech OID\n"); - } - - res = 0; -diff --git a/utils/idmapd/Makefile.am b/utils/idmapd/Makefile.am -index 4328e41..58b33ec 100644 ---- a/utils/idmapd/Makefile.am -+++ b/utils/idmapd/Makefile.am -@@ -16,7 +16,7 @@ idmapd_SOURCES = \ - nfs_idmap.h \ - queue.h - --idmapd_LDADD = -levent -lnfsidmap ../../support/nfs/libnfs.a -+idmapd_LDADD = $(LIBEVENT) $(LIBNFSIDMAP) ../../support/nfs/libnfs.a - - MAINTAINERCLEANFILES = Makefile.in - -diff --git a/utils/idmapd/idmapd.c b/utils/idmapd/idmapd.c -index 19d9114..e80efb4 100644 ---- a/utils/idmapd/idmapd.c -+++ b/utils/idmapd/idmapd.c -@@ -778,8 +778,8 @@ nfsopen(struct idmap_client *ic) - } else { - event_set(&ic->ic_event, ic->ic_fd, EV_READ, nfscb, ic); - event_add(&ic->ic_event, NULL); -- fcntl(ic->ic_dirfd, F_SETSIG, 0); - fcntl(ic->ic_dirfd, F_NOTIFY, 0); -+ fcntl(ic->ic_dirfd, F_SETSIG, 0); - if (verbose > 0) - xlog_warn("Opened %s", ic->ic_path); - } -diff --git a/utils/mount/Makefile.am b/utils/mount/Makefile.am -index 7bc3e2b..7627854 100644 ---- a/utils/mount/Makefile.am -+++ b/utils/mount/Makefile.am -@@ -24,7 +24,8 @@ EXTRA_DIST += nfsmount.conf - endif - - mount_nfs_LDADD = ../../support/nfs/libnfs.a \ -- ../../support/export/libexport.a -+ ../../support/export/libexport.a \ -+ $(LIBTIRPC) - - mount_nfs_SOURCES = $(mount_common) - -diff --git a/utils/mount/mount_libmount.c b/utils/mount/mount_libmount.c -index e450d79..e8f17a9 100644 ---- a/utils/mount/mount_libmount.c -+++ b/utils/mount/mount_libmount.c -@@ -346,6 +346,21 @@ static int mount_main(struct libmnt_context *cxt, int argc, char **argv) - - if (chk_mountpoint(mount_point)) - goto err; -+ -+ /* -+ * The libmount strictly uses only options from fstab if running in -+ * restricted mode (suid, non-root user). This is done in -+ * mnt_context_prepare_mount() by default. -+ * -+ * We have to read fstab before nfsmount.conf, otherwise the options -+ * from nfsmount.conf will be ignored (overwrited). -+ */ -+ rc = mnt_context_apply_fstab(cxt); -+ if (rc) { -+ nfs_error(_("%s: failed to apply fstab options\n"), progname); -+ goto err; -+ } -+ - /* - * Concatenate mount options from the configuration file - */ -diff --git a/utils/mount/nfs.man b/utils/mount/nfs.man -index ce40933..0d20cf0 100644 ---- a/utils/mount/nfs.man -+++ b/utils/mount/nfs.man -@@ -372,14 +372,8 @@ Valid security flavors are - .BR sys , - .BR krb5 , - .BR krb5i , --.BR krb5p , --.BR lkey , --.BR lkeyi , --.BR lkeyp , --.BR spkm , --.BR spkmi , - and --.BR spkmp . -+.BR krb5p , - Refer to the SECURITY CONSIDERATIONS section for details. - .TP 1.5i - .BR sharecache " / " nosharecache -@@ -1416,7 +1410,7 @@ security flavor encrypts every RPC request - to prevent data exposure during network transit; however, - expect some performance impact - when using integrity checking or encryption. --Similar support for other forms of cryptographic security (such as lipkey and SPKM3) -+Similar support for other forms of cryptographic security - is also available. - .P - The NFS version 4 protocol allows -@@ -1561,10 +1555,10 @@ To ensure that the saved mount options are not erased during a remount, - specify either the local mount directory, or the server hostname and - export pathname, but not both, during a remount. For example, - .P --.NF --.TA 2.5i -+.nf -+.ta 8n - mount -o remount,ro /mnt --.FI -+.fi - .P - merges the mount option - .B ro -diff --git a/utils/mount/nfs_mount.h b/utils/mount/nfs_mount.h -index 2becfb1..ec30c9b 100644 ---- a/utils/mount/nfs_mount.h -+++ b/utils/mount/nfs_mount.h -@@ -75,9 +75,6 @@ struct nfs_mount_data { - #define AUTH_GSS_LKEY 390006 - #define AUTH_GSS_LKEYI 390007 - #define AUTH_GSS_LKEYP 390008 --#define AUTH_GSS_SPKM 390009 --#define AUTH_GSS_SPKMI 390010 --#define AUTH_GSS_SPKMP 390011 - #endif - - int nfsmount(const char *, const char *, int , char **, int, int); -diff --git a/utils/mount/nfsmount.c b/utils/mount/nfsmount.c -index 1298fe4..930622d 100644 ---- a/utils/mount/nfsmount.c -+++ b/utils/mount/nfsmount.c -@@ -294,18 +294,6 @@ parse_options(char *old_opts, struct nfs_mount_data *data, - data->pseudoflavor = AUTH_GSS_KRB5I; - else if (!strcmp(secflavor, "krb5p")) - data->pseudoflavor = AUTH_GSS_KRB5P; -- else if (!strcmp(secflavor, "lipkey")) -- data->pseudoflavor = AUTH_GSS_LKEY; -- else if (!strcmp(secflavor, "lipkey-i")) -- data->pseudoflavor = AUTH_GSS_LKEYI; -- else if (!strcmp(secflavor, "lipkey-p")) -- data->pseudoflavor = AUTH_GSS_LKEYP; -- else if (!strcmp(secflavor, "spkm3")) -- data->pseudoflavor = AUTH_GSS_SPKM; -- else if (!strcmp(secflavor, "spkm3i")) -- data->pseudoflavor = AUTH_GSS_SPKMI; -- else if (!strcmp(secflavor, "spkm3p")) -- data->pseudoflavor = AUTH_GSS_SPKMP; - else if (sloppy) - continue; - else { -diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c -index 314a806..e09aa7c 100644 ---- a/utils/mount/stropts.c -+++ b/utils/mount/stropts.c -@@ -540,6 +540,8 @@ nfs_rewrite_pmap_mount_options(struct mount_options *options) - errno = EOPNOTSUPP; - else if (rpc_createerr.cf_stat == RPC_AUTHERROR) - errno = EACCES; -+ else if (rpc_createerr.cf_stat == RPC_TIMEDOUT) -+ errno = ETIMEDOUT; - else if (rpc_createerr.cf_error.re_errno != 0) - errno = rpc_createerr.cf_error.re_errno; - return 0; -@@ -665,9 +667,10 @@ static int nfs_try_mount_v3v2(struct nfsmount_info *mi) - case EHOSTUNREACH: - continue; - default: -- break; -+ goto out; - } - } -+out: - return ret; - } - -@@ -751,9 +754,10 @@ static int nfs_try_mount_v4(struct nfsmount_info *mi) - case EHOSTUNREACH: - continue; - default: -- break; -+ goto out; - } - } -+out: - return ret; - } - -@@ -907,7 +911,8 @@ static int nfsmount_parent(struct nfsmount_info *mi) - if (nfs_try_mount(mi)) - return EX_SUCCESS; - -- if (nfs_is_permanent_error(errno)) { -+ /* retry background mounts when the server is not up */ -+ if (nfs_is_permanent_error(errno) && errno != EOPNOTSUPP) { - mount_error(mi->spec, mi->node, errno); - return EX_FAIL; - } -@@ -942,7 +947,8 @@ static int nfsmount_child(struct nfsmount_info *mi) - if (nfs_try_mount(mi)) - return EX_SUCCESS; - -- if (nfs_is_permanent_error(errno)) -+ /* retry background mounts when the server is not up */ -+ if (nfs_is_permanent_error(errno) && errno != EOPNOTSUPP) - break; - - if (time(NULL) > timeout) -diff --git a/utils/mountd/Makefile.am b/utils/mountd/Makefile.am -index eba81fc..7db968b 100644 ---- a/utils/mountd/Makefile.am -+++ b/utils/mountd/Makefile.am -@@ -12,7 +12,7 @@ mountd_SOURCES = mountd.c mount_dispatch.c auth.c rmtab.c cache.c \ - mountd_LDADD = ../../support/export/libexport.a \ - ../../support/nfs/libnfs.a \ - ../../support/misc/libmisc.a \ -- $(LIBBSD) $(LIBWRAP) $(LIBNSL) $(LIBBLKID) -+ $(LIBBSD) $(LIBWRAP) $(LIBNSL) $(LIBBLKID) $(LIBDL) $(LIBTIRPC) - mountd_CPPFLAGS = $(AM_CPPFLAGS) $(CPPFLAGS) \ - -I$(top_builddir)/support/include \ - -I$(top_srcdir)/support/export -diff --git a/utils/mountd/auth.c b/utils/mountd/auth.c -index ccc849a..508040a 100644 ---- a/utils/mountd/auth.c -+++ b/utils/mountd/auth.c -@@ -112,15 +112,23 @@ auth_reload() - return counter; - } - -+static char *get_client_ipaddr_name(const struct sockaddr *caller) -+{ -+ char buf[INET6_ADDRSTRLEN + 1]; -+ -+ buf[0] = '$'; -+ host_ntop(caller, buf + 1, sizeof(buf) - 1); -+ return strdup(buf); -+} -+ - static char * - get_client_hostname(const struct sockaddr *caller, struct addrinfo *ai, - enum auth_error *error) - { -- char buf[INET6_ADDRSTRLEN]; - char *n; - - if (use_ipaddr) -- return strdup(host_ntop(caller, buf, sizeof(buf))); -+ return get_client_ipaddr_name(caller); - n = client_compose(ai); - *error = unknown_host; - if (!n) -@@ -131,6 +139,23 @@ get_client_hostname(const struct sockaddr *caller, struct addrinfo *ai, - return strdup("DEFAULT"); - } - -+bool ipaddr_client_matches(nfs_export *exp, struct addrinfo *ai) -+{ -+ return client_check(exp->m_client, ai); -+} -+ -+bool namelist_client_matches(nfs_export *exp, char *dom) -+{ -+ return client_member(dom, exp->m_client->m_hostname); -+} -+ -+bool client_matches(nfs_export *exp, char *dom, struct addrinfo *ai) -+{ -+ if (is_ipaddr_client(dom)) -+ return ipaddr_client_matches(exp, ai); -+ return namelist_client_matches(exp, dom); -+} -+ - /* return static nfs_export with details filled in */ - static nfs_export * - auth_authenticate_newcache(const struct sockaddr *caller, -@@ -155,9 +180,10 @@ auth_authenticate_newcache(const struct sockaddr *caller, - for (exp = exportlist[i].p_head; exp; exp = exp->m_next) { - if (strcmp(path, exp->m_export.e_path)) - continue; -- if (!use_ipaddr && !client_member(my_client.m_hostname, exp->m_client->m_hostname)) -+ if (!client_matches(exp, my_client.m_hostname, ai)) - continue; -- if (use_ipaddr && !client_check(exp->m_client, ai)) -+ if (exp->m_export.e_flags & NFSEXP_V4ROOT) -+ /* not acceptable for v[23] export */ - continue; - break; - } -@@ -187,10 +213,6 @@ auth_authenticate_internal(const struct sockaddr *caller, const char *path, - return NULL; - } - } -- if (exp->m_export.e_flags & NFSEXP_V4ROOT) { -- *error = no_entry; -- return NULL; -- } - if (!(exp->m_export.e_flags & NFSEXP_INSECURE_PORT) && - nfs_get_port(caller) >= IPPORT_RESERVED) { - *error = illegal_port; -diff --git a/utils/mountd/cache.c b/utils/mountd/cache.c -index d2ae456..7d80432 100644 ---- a/utils/mountd/cache.c -+++ b/utils/mountd/cache.c -@@ -84,7 +84,6 @@ static void auth_unix_ip(FILE *f) - char ipaddr[INET6_ADDRSTRLEN]; - char *client = NULL; - struct addrinfo *tmp = NULL; -- struct addrinfo *ai = NULL; - if (readline(fileno(f), &lbuf, &lbuflen) != 1) - return; - -@@ -107,12 +106,16 @@ static void auth_unix_ip(FILE *f) - - /* addr is a valid, interesting address, find the domain name... */ - if (!use_ipaddr) { -+ struct addrinfo *ai = NULL; -+ - ai = client_resolve(tmp->ai_addr); -+ if (ai == NULL) -+ goto out; - client = client_compose(ai); - freeaddrinfo(ai); -+ if (!client) -+ goto out; - } -- freeaddrinfo(tmp); -- - qword_print(f, "nfsd"); - qword_print(f, ipaddr); - qword_printuint(f, time(0) + DEFAULT_TTL); -@@ -124,6 +127,9 @@ static void auth_unix_ip(FILE *f) - xlog(D_CALL, "auth_unix_ip: client %p '%s'", client, client?client: "DEFAULT"); - - free(client); -+out: -+ freeaddrinfo(tmp); -+ - } - - static void auth_unix_gid(FILE *f) -@@ -495,6 +501,21 @@ static bool match_fsid(struct parsed_fsid *parsed, nfs_export *exp, char *path) - return false; - } - -+struct addrinfo *lookup_client_addr(char *dom) -+{ -+ struct addrinfo *ret; -+ struct addrinfo *tmp; -+ -+ dom++; /* skip initial "$" */ -+ -+ tmp = host_pton(dom); -+ if (tmp == NULL) -+ return NULL; -+ ret = client_resolve(tmp->ai_addr); -+ freeaddrinfo(tmp); -+ return ret; -+} -+ - static void nfsd_fh(FILE *f) - { - /* request are: -@@ -538,6 +559,12 @@ static void nfsd_fh(FILE *f) - - auth_reload(); - -+ if (is_ipaddr_client(dom)) { -+ ai = lookup_client_addr(dom); -+ if (!ai) -+ goto out; -+ } -+ - /* Now determine export point for this fsid/domain */ - for (i=0 ; i < MCL_MAXTYPES; i++) { - nfs_export *next_exp; -@@ -568,7 +595,8 @@ static void nfsd_fh(FILE *f) - next_exp = exp->m_next; - } - -- if (!use_ipaddr && !client_member(dom, exp->m_client->m_hostname)) -+ if (!is_ipaddr_client(dom) -+ && !namelist_client_matches(exp, dom)) - continue; - if (exp->m_export.e_mountpoint && - !is_mountpoint(exp->m_export.e_mountpoint[0]? -@@ -578,29 +606,29 @@ static void nfsd_fh(FILE *f) - - if (!match_fsid(&parsed, exp, path)) - continue; -- if (use_ipaddr) { -- if (ai == NULL) { -- struct addrinfo *tmp; -- tmp = host_pton(dom); -- if (tmp == NULL) -- goto out; -- ai = client_resolve(tmp->ai_addr); -- freeaddrinfo(tmp); -- } -- if (!client_check(exp->m_client, ai)) -- continue; -- } -+ if (is_ipaddr_client(dom) -+ && !ipaddr_client_matches(exp, ai)) -+ continue; - if (!found || subexport(&exp->m_export, found)) { - found = &exp->m_export; - free(found_path); - found_path = strdup(path); - if (found_path == NULL) - goto out; -- } else if (strcmp(found->e_path, exp->m_export.e_path) -+ } else if (strcmp(found->e_path, exp->m_export.e_path) != 0 - && !subexport(found, &exp->m_export)) - { - xlog(L_WARNING, "%s and %s have same filehandle for %s, using first", - found_path, path, dom); -+ } else { -+ /* same path, if one is V4ROOT, choose the other */ -+ if (found->e_flags & NFSEXP_V4ROOT) { -+ found = &exp->m_export; -+ free(found_path); -+ found_path = strdup(path); -+ if (found_path == NULL) -+ goto out; -+ } - } - } - } -@@ -742,14 +770,6 @@ static int path_matches(nfs_export *exp, char *path) - } - - static int --client_matches(nfs_export *exp, char *dom, struct addrinfo *ai) --{ -- if (use_ipaddr) -- return client_check(exp->m_client, ai); -- return client_member(dom, exp->m_client->m_hostname); --} -- --static int - export_matches(nfs_export *exp, char *dom, char *path, struct addrinfo *ai) - { - return path_matches(exp, path) && client_matches(exp, dom, ai); -@@ -772,10 +792,14 @@ lookup_export(char *dom, char *path, struct addrinfo *ai) - found_type = i; - continue; - } -- -- /* Always prefer non-V4ROOT mounts */ -- if (found->m_export.e_flags & NFSEXP_V4ROOT) -+ /* Always prefer non-V4ROOT exports */ -+ if (exp->m_export.e_flags & NFSEXP_V4ROOT) -+ continue; -+ if (found->m_export.e_flags & NFSEXP_V4ROOT) { -+ found = exp; -+ found_type = i; - continue; -+ } - - /* If one is a CROSSMOUNT, then prefer the longest path */ - if (((found->m_export.e_flags & NFSEXP_CROSSMOUNT) || -@@ -802,6 +826,229 @@ lookup_export(char *dom, char *path, struct addrinfo *ai) - return found; - } - -+#ifdef HAVE_NFS_PLUGIN_H -+#include -+#include -+ -+/* -+ * Walk through a set of FS locations and build a set of export options. -+ * Returns true if all went to plan; otherwise, false. -+ */ -+static _Bool -+locations_to_options(struct jp_ops *ops, nfs_fsloc_set_t locations, -+ char *options, size_t remaining, int *ttl) -+{ -+ char *server, *last_path, *rootpath, *ptr; -+ _Bool seen = false; -+ -+ last_path = NULL; -+ rootpath = NULL; -+ server = NULL; -+ ptr = options; -+ *ttl = 0; -+ -+ for (;;) { -+ enum jp_status status; -+ int len; -+ -+ status = ops->jp_get_next_location(locations, &server, -+ &rootpath, ttl); -+ if (status == JP_EMPTY) -+ break; -+ if (status != JP_OK) { -+ xlog(D_GENERAL, "%s: failed to parse location: %s", -+ __func__, ops->jp_error(status)); -+ goto out_false; -+ } -+ xlog(D_GENERAL, "%s: Location: %s:%s", -+ __func__, server, rootpath); -+ -+ if (last_path && strcmp(rootpath, last_path) == 0) { -+ len = snprintf(ptr, remaining, "+%s", server); -+ if (len < 0) { -+ xlog(D_GENERAL, "%s: snprintf: %m", __func__); -+ goto out_false; -+ } -+ if ((size_t)len >= remaining) { -+ xlog(D_GENERAL, "%s: options buffer overflow", __func__); -+ goto out_false; -+ } -+ remaining -= (size_t)len; -+ ptr += len; -+ } else { -+ if (last_path == NULL) -+ len = snprintf(ptr, remaining, "refer=%s@%s", -+ rootpath, server); -+ else -+ len = snprintf(ptr, remaining, ":%s@%s", -+ rootpath, server); -+ if (len < 0) { -+ xlog(D_GENERAL, "%s: snprintf: %m", __func__); -+ goto out_false; -+ } -+ if ((size_t)len >= remaining) { -+ xlog(D_GENERAL, "%s: options buffer overflow", -+ __func__); -+ goto out_false; -+ } -+ remaining -= (size_t)len; -+ ptr += len; -+ last_path = rootpath; -+ } -+ -+ seen = true; -+ free(rootpath); -+ free(server); -+ } -+ -+ xlog(D_CALL, "%s: options='%s', ttl=%d", -+ __func__, options, *ttl); -+ return seen; -+ -+out_false: -+ free(rootpath); -+ free(server); -+ return false; -+} -+ -+/* -+ * Walk through the set of FS locations and build an exportent. -+ * Returns pointer to an exportent if "junction" refers to a junction. -+ * -+ * Returned exportent points to static memory. -+ */ -+static struct exportent *do_locations_to_export(struct jp_ops *ops, -+ nfs_fsloc_set_t locations, const char *junction, -+ char *options, size_t options_len) -+{ -+ struct exportent *exp; -+ int ttl; -+ -+ if (!locations_to_options(ops, locations, options, options_len, &ttl)) -+ return NULL; -+ -+ exp = mkexportent("*", (char *)junction, options); -+ if (exp == NULL) { -+ xlog(L_ERROR, "%s: Failed to construct exportent", __func__); -+ return NULL; -+ } -+ -+ exp->e_uuid = NULL; -+ exp->e_ttl = ttl; -+ return exp; -+} -+ -+/* -+ * Convert set of FS locations to an exportent. Returns pointer to -+ * an exportent if "junction" refers to a junction. -+ * -+ * Returned exportent points to static memory. -+ */ -+static struct exportent *locations_to_export(struct jp_ops *ops, -+ nfs_fsloc_set_t locations, const char *junction) -+{ -+ struct exportent *exp; -+ char *options; -+ -+ options = malloc(BUFSIZ); -+ if (options == NULL) { -+ xlog(D_GENERAL, "%s: failed to allocate options buffer", -+ __func__); -+ return NULL; -+ } -+ options[0] = '\0'; -+ -+ exp = do_locations_to_export(ops, locations, junction, -+ options, BUFSIZ); -+ -+ free(options); -+ return exp; -+} -+ -+/* -+ * Retrieve locations information in "junction" and dump it to the -+ * kernel. Returns pointer to an exportent if "junction" refers -+ * to a junction. -+ * -+ * Returned exportent points to static memory. -+ */ -+static struct exportent *invoke_junction_ops(void *handle, -+ const char *junction) -+{ -+ nfs_fsloc_set_t locations; -+ struct exportent *exp; -+ enum jp_status status; -+ struct jp_ops *ops; -+ char *error; -+ -+ ops = (struct jp_ops *)dlsym(handle, "nfs_junction_ops"); -+ error = dlerror(); -+ if (error != NULL) { -+ xlog(D_GENERAL, "%s: dlsym(jp_junction_ops): %s", -+ __func__, error); -+ return NULL; -+ } -+ if (ops->jp_api_version != JP_API_VERSION) { -+ xlog(D_GENERAL, "%s: unrecognized junction API version: %u", -+ __func__, ops->jp_api_version); -+ return NULL; -+ } -+ -+ status = ops->jp_init(false); -+ if (status != JP_OK) { -+ xlog(D_GENERAL, "%s: failed to resolve %s: %s", -+ __func__, junction, ops->jp_error(status)); -+ return NULL; -+ } -+ -+ status = ops->jp_get_locations(junction, &locations); -+ if (status != JP_OK) { -+ xlog(D_GENERAL, "%s: failed to resolve %s: %s", -+ __func__, junction, ops->jp_error(status)); -+ return NULL; -+ } -+ -+ exp = locations_to_export(ops, locations, junction); -+ -+ ops->jp_put_locations(locations); -+ ops->jp_done(); -+ return exp; -+} -+ -+/* -+ * Load the junction plug-in, then try to resolve "pathname". -+ * Returns pointer to an initialized exportent if "junction" -+ * refers to a junction, or NULL if not. -+ * -+ * Returned exportent points to static memory. -+ */ -+static struct exportent *lookup_junction(const char *pathname) -+{ -+ struct exportent *exp; -+ void *handle; -+ -+ handle = dlopen("libnfsjunct.so", RTLD_NOW); -+ if (handle == NULL) { -+ xlog(D_GENERAL, "%s: dlopen: %s", __func__, dlerror()); -+ return NULL; -+ } -+ (void)dlerror(); /* Clear any error */ -+ -+ exp = invoke_junction_ops(handle, pathname); -+ -+ /* We could leave it loaded to make junction resolution -+ * faster next time. However, if we want to replace the -+ * library, that would require restarting mountd. */ -+ (void)dlclose(handle); -+ return exp; -+} -+#else /* !HAVE_NFS_PLUGIN_H */ -+static inline struct exportent *lookup_junction(const char *UNUSED(pathname)) -+{ -+ return NULL; -+} -+#endif /* !HAVE_NFS_PLUGIN_H */ -+ - static void nfsd_export(FILE *f) - { - /* requests are: -@@ -834,13 +1081,9 @@ static void nfsd_export(FILE *f) - - auth_reload(); - -- if (use_ipaddr) { -- struct addrinfo *tmp; -- tmp = host_pton(dom); -- if (tmp == NULL) -- goto out; -- ai = client_resolve(tmp->ai_addr); -- freeaddrinfo(tmp); -+ if (is_ipaddr_client(dom)) { -+ ai = lookup_client_addr(dom); -+ if (!ai) - goto out; - } - -@@ -854,7 +1097,7 @@ static void nfsd_export(FILE *f) - dump_to_cache(f, dom, path, NULL); - } - } else { -- dump_to_cache(f, dom, path, NULL); -+ dump_to_cache(f, dom, path, lookup_junction(path)); - } - out: - xlog(D_CALL, "nfsd_export: found %p path %s", found, path ? path : NULL); -diff --git a/utils/mountd/fsloc.c b/utils/mountd/fsloc.c -index e2add2d..bc737d1 100644 ---- a/utils/mountd/fsloc.c -+++ b/utils/mountd/fsloc.c -@@ -40,12 +40,12 @@ static void replicas_print(struct servers *sp) - { - int i; - if (!sp) { -- xlog(L_NOTICE, "NULL replicas pointer\n"); -+ xlog(L_NOTICE, "NULL replicas pointer"); - return; - } -- xlog(L_NOTICE, "replicas listsize=%i\n", sp->h_num); -+ xlog(L_NOTICE, "replicas listsize=%i", sp->h_num); - for (i=0; ih_num; i++) { -- xlog(L_NOTICE, " %s:%s\n", -+ xlog(L_NOTICE, " %s:%s", - sp->h_mp[i]->h_host, sp->h_mp[i]->h_path); - } - } -@@ -120,23 +120,37 @@ static struct servers *parse_list(char **list) - */ - static struct servers *method_list(char *data) - { -- char *copy, *ptr=data; -+ char *copy, *ptr=data, *p; - char **list; - int i, listsize; - struct servers *rv=NULL; -+ bool v6esc = false; - -- xlog(L_NOTICE, "method_list(%s)\n", data); -+ xlog(L_NOTICE, "method_list(%s)", data); - for (ptr--, listsize=1; ptr; ptr=index(ptr, ':'), listsize++) - ptr++; - list = malloc(listsize * sizeof(char *)); - copy = strdup(data); - if (copy) -- xlog(L_NOTICE, "converted to %s\n", copy); -+ xlog(L_NOTICE, "converted to %s", copy); - if (list && copy) { - ptr = copy; -- for (i=0; im_export; - - dupexportent(&eep, &pseudo_root.m_export); -- eep.e_hostname = strdup(curexp->e_hostname); -+ eep.e_hostname = curexp->e_hostname; - strncpy(eep.e_path, path, sizeof(eep.e_path)); - if (strcmp(path, "/") != 0) - eep.e_flags &= ~NFSEXP_FSID; -@@ -149,13 +150,13 @@ static int v4root_add_parents(nfs_export *exp) - "pseudo export for '%s'", exp->m_export.e_path); - return -ENOMEM; - } -- for (ptr = path + 1; ptr; ptr = strchr(ptr, '/')) { -+ for (ptr = path; ptr; ptr = strchr(ptr, '/')) { - int ret; - char saved; - - saved = *ptr; - *ptr = '\0'; -- ret = pseudofs_update(hostname, path, exp); -+ ret = pseudofs_update(hostname, *path ? path : "/", exp); - if (ret) - return ret; - *ptr = saved; -@@ -192,6 +193,13 @@ v4root_set() - */ - continue; - -+ if (strcmp(exp->m_export.e_path, "/") == 0 && -+ !(exp->m_export.e_flags & NFSEXP_FSID)) { -+ /* Force '/' to be exported as fsid == 0*/ -+ exp->m_export.e_flags |= NFSEXP_FSID; -+ exp->m_export.e_fsid = 0; -+ } -+ - v4root_add_parents(exp); - /* XXX: error handling! */ - } -diff --git a/utils/nfsd/Makefile.am b/utils/nfsd/Makefile.am -index c4c6fb0..1536065 100644 ---- a/utils/nfsd/Makefile.am -+++ b/utils/nfsd/Makefile.am -@@ -8,7 +8,7 @@ KPREFIX = @kprefix@ - sbin_PROGRAMS = nfsd - - nfsd_SOURCES = nfsd.c nfssvc.c --nfsd_LDADD = ../../support/nfs/libnfs.a -+nfsd_LDADD = ../../support/nfs/libnfs.a $(LIBTIRPC) - - MAINTAINERCLEANFILES = Makefile.in - -diff --git a/utils/nfsd/nfsd.c b/utils/nfsd/nfsd.c -index 8bc5d3a..2a3f5cc 100644 ---- a/utils/nfsd/nfsd.c -+++ b/utils/nfsd/nfsd.c -@@ -27,6 +27,10 @@ - #include "nfssvc.h" - #include "xlog.h" - -+#ifndef NFSD_NPROC -+#define NFSD_NPROC 8 -+#endif -+ - static void usage(const char *); - - static struct option longopts[] = -@@ -90,7 +94,7 @@ nfsd_enable_protos(unsigned int *proto4, unsigned int *proto6) - int - main(int argc, char **argv) - { -- int count = 1, c, error = 0, portnum = 0, fd, found_one; -+ int count = NFSD_NPROC, c, error = 0, portnum = 0, fd, found_one; - char *p, *progname, *port; - char *haddr = NULL; - int socket_up = 0; -diff --git a/utils/nfsd/nfsd.man b/utils/nfsd/nfsd.man -index d8988d2..1cf9296 100644 ---- a/utils/nfsd/nfsd.man -+++ b/utils/nfsd/nfsd.man -@@ -38,7 +38,7 @@ request on all known network addresses. This may change in future - releases of the Linux Kernel. - .TP - .B \-p " or " \-\-port port --specify a diferent port to listen on for NFS requests. By default, -+specify a different port to listen on for NFS requests. By default, - .B rpc.nfsd - will listen on port 2049. - .TP -diff --git a/utils/nfsdcld/Makefile.am b/utils/nfsdcld/Makefile.am -new file mode 100644 -index 0000000..f320dff ---- /dev/null -+++ b/utils/nfsdcld/Makefile.am -@@ -0,0 +1,14 @@ -+## Process this file with automake to produce Makefile.in -+ -+man8_MANS = nfsdcld.man -+EXTRA_DIST = $(man8_MANS) -+ -+AM_CFLAGS += -D_LARGEFILE64_SOURCE -+sbin_PROGRAMS = nfsdcld -+ -+nfsdcld_SOURCES = nfsdcld.c sqlite.c -+ -+nfsdcld_LDADD = ../../support/nfs/libnfs.a $(LIBEVENT) $(LIBSQLITE) -+ -+MAINTAINERCLEANFILES = Makefile.in -+ -diff --git a/utils/nfsdcld/nfsdcld.c b/utils/nfsdcld/nfsdcld.c -new file mode 100644 -index 0000000..2f0b004 ---- /dev/null -+++ b/utils/nfsdcld/nfsdcld.c -@@ -0,0 +1,527 @@ -+/* -+ * nfsdcld.c -- NFSv4 client name tracking daemon -+ * -+ * Copyright (C) 2011 Red Hat, Jeff Layton -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version 2 -+ * of the License, or (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ */ -+ -+#ifdef HAVE_CONFIG_H -+#include "config.h" -+#endif /* HAVE_CONFIG_H */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "xlog.h" -+#include "nfslib.h" -+#include "cld.h" -+#include "sqlite.h" -+ -+#ifndef PIPEFS_DIR -+#define PIPEFS_DIR NFS_STATEDIR "/rpc_pipefs" -+#endif -+ -+#define DEFAULT_CLD_PATH PIPEFS_DIR "/nfsd/cld" -+ -+#define UPCALL_VERSION 1 -+ -+/* private data structures */ -+struct cld_client { -+ int cl_fd; -+ struct event cl_event; -+ struct cld_msg cl_msg; -+}; -+ -+/* global variables */ -+static char *pipepath = DEFAULT_CLD_PATH; -+static int inotify_fd = -1; -+static struct event pipedir_event; -+ -+static struct option longopts[] = -+{ -+ { "help", 0, NULL, 'h' }, -+ { "foreground", 0, NULL, 'F' }, -+ { "debug", 0, NULL, 'd' }, -+ { "pipe", 1, NULL, 'p' }, -+ { "storagedir", 1, NULL, 's' }, -+ { NULL, 0, 0, 0 }, -+}; -+ -+/* forward declarations */ -+static void cldcb(int UNUSED(fd), short which, void *data); -+ -+static void -+usage(char *progname) -+{ -+ printf("%s [ -hFd ] [ -p pipe ] [ -s dir ]\n", progname); -+} -+ -+#define INOTIFY_EVENT_MAX (sizeof(struct inotify_event) + NAME_MAX) -+ -+static int -+cld_pipe_open(struct cld_client *clnt) -+{ -+ int fd; -+ -+ xlog(D_GENERAL, "%s: opening upcall pipe %s", __func__, pipepath); -+ fd = open(pipepath, O_RDWR, 0); -+ if (fd < 0) { -+ xlog(L_ERROR, "%s: open of %s failed: %m", __func__, pipepath); -+ return -errno; -+ } -+ -+ if (clnt->cl_event.ev_flags & EVLIST_INIT) -+ event_del(&clnt->cl_event); -+ if (clnt->cl_fd >= 0) -+ close(clnt->cl_fd); -+ -+ clnt->cl_fd = fd; -+ event_set(&clnt->cl_event, clnt->cl_fd, EV_READ, cldcb, clnt); -+ /* event_add is done by the caller */ -+ return 0; -+} -+ -+static void -+cld_inotify_cb(int UNUSED(fd), short which, void *data) -+{ -+ int ret; -+ size_t elen; -+ ssize_t rret; -+ char evbuf[INOTIFY_EVENT_MAX]; -+ char *dirc = NULL, *pname; -+ struct inotify_event *event = (struct inotify_event *)evbuf; -+ struct cld_client *clnt = data; -+ -+ if (which != EV_READ) -+ return; -+ -+ xlog(D_GENERAL, "%s: called for EV_READ", __func__); -+ -+ dirc = strndup(pipepath, PATH_MAX); -+ if (!dirc) { -+ xlog(L_ERROR, "%s: unable to allocate memory", __func__); -+ goto out; -+ } -+ -+ rret = read(inotify_fd, evbuf, INOTIFY_EVENT_MAX); -+ if (rret < 0) { -+ xlog(L_ERROR, "%s: read from inotify fd failed: %m", __func__); -+ goto out; -+ } -+ -+ /* check to see if we have a filename in the evbuf */ -+ if (!event->len) { -+ xlog(D_GENERAL, "%s: no filename in inotify event", __func__); -+ goto out; -+ } -+ -+ pname = basename(dirc); -+ elen = strnlen(event->name, event->len); -+ -+ /* does the filename match our pipe? */ -+ if (strlen(pname) != elen || memcmp(pname, event->name, elen)) { -+ xlog(D_GENERAL, "%s: wrong filename (%s)", __func__, -+ event->name); -+ goto out; -+ } -+ -+ ret = cld_pipe_open(clnt); -+ switch (ret) { -+ case 0: -+ /* readd the event for the cl_event pipe */ -+ event_add(&clnt->cl_event, NULL); -+ break; -+ case -ENOENT: -+ /* pipe must have disappeared, wait for it to come back */ -+ goto out; -+ default: -+ /* anything else is fatal */ -+ xlog(L_FATAL, "%s: unable to open new pipe (%d). Aborting.", -+ ret, __func__); -+ exit(ret); -+ } -+ -+out: -+ event_add(&pipedir_event, NULL); -+ free(dirc); -+} -+ -+static int -+cld_inotify_setup(void) -+{ -+ int ret; -+ char *dirc, *dname; -+ -+ dirc = strndup(pipepath, PATH_MAX); -+ if (!dirc) { -+ xlog_err("%s: unable to allocate memory", __func__); -+ ret = -ENOMEM; -+ goto out_free; -+ } -+ -+ dname = dirname(dirc); -+ -+ inotify_fd = inotify_init(); -+ if (inotify_fd < 0) { -+ xlog_err("%s: inotify_init failed: %m", __func__); -+ ret = -errno; -+ goto out_free; -+ } -+ -+ ret = inotify_add_watch(inotify_fd, dname, IN_CREATE); -+ if (ret < 0) { -+ xlog_err("%s: inotify_add_watch failed: %m", __func__); -+ ret = -errno; -+ goto out_err; -+ } -+ -+out_free: -+ free(dirc); -+ return 0; -+out_err: -+ close(inotify_fd); -+ goto out_free; -+} -+ -+/* -+ * Set an inotify watch on the directory that should contain the pipe, and then -+ * try to open it. If it fails with anything but -ENOENT, return the error -+ * immediately. -+ * -+ * If it succeeds, then set up the pipe event handler. At that point, set up -+ * the inotify event handler and go ahead and return success. -+ */ -+static int -+cld_pipe_init(struct cld_client *clnt) -+{ -+ int ret; -+ -+ xlog(D_GENERAL, "%s: init pipe handlers", __func__); -+ -+ ret = cld_inotify_setup(); -+ if (ret != 0) -+ goto out; -+ -+ clnt->cl_fd = -1; -+ ret = cld_pipe_open(clnt); -+ switch (ret) { -+ case 0: -+ /* add the event and we're good to go */ -+ event_add(&clnt->cl_event, NULL); -+ break; -+ case -ENOENT: -+ /* ignore this error -- cld_inotify_cb will handle it */ -+ ret = 0; -+ break; -+ default: -+ /* anything else is fatal */ -+ close(inotify_fd); -+ goto out; -+ } -+ -+ /* set event for inotify read */ -+ event_set(&pipedir_event, inotify_fd, EV_READ, cld_inotify_cb, clnt); -+ event_add(&pipedir_event, NULL); -+out: -+ return ret; -+} -+ -+static void -+cld_not_implemented(struct cld_client *clnt) -+{ -+ int ret; -+ ssize_t bsize, wsize; -+ struct cld_msg *cmsg = &clnt->cl_msg; -+ -+ xlog(D_GENERAL, "%s: downcalling with not implemented error", __func__); -+ -+ /* set up reply */ -+ cmsg->cm_status = -EOPNOTSUPP; -+ -+ bsize = sizeof(*cmsg); -+ -+ wsize = atomicio((void *)write, clnt->cl_fd, cmsg, bsize); -+ if (wsize != bsize) -+ xlog(L_ERROR, "%s: problem writing to cld pipe (%ld): %m", -+ __func__, wsize); -+ -+ /* reopen pipe, just to be sure */ -+ ret = cld_pipe_open(clnt); -+ if (ret) { -+ xlog(L_FATAL, "%s: unable to reopen pipe: %d", __func__, ret); -+ exit(ret); -+ } -+} -+ -+static void -+cld_create(struct cld_client *clnt) -+{ -+ int ret; -+ ssize_t bsize, wsize; -+ struct cld_msg *cmsg = &clnt->cl_msg; -+ -+ xlog(D_GENERAL, "%s: create client record.", __func__); -+ -+ ret = sqlite_insert_client(cmsg->cm_u.cm_name.cn_id, -+ cmsg->cm_u.cm_name.cn_len); -+ -+ cmsg->cm_status = ret ? -EREMOTEIO : ret; -+ -+ bsize = sizeof(*cmsg); -+ -+ xlog(D_GENERAL, "Doing downcall with status %d", cmsg->cm_status); -+ wsize = atomicio((void *)write, clnt->cl_fd, cmsg, bsize); -+ if (wsize != bsize) { -+ xlog(L_ERROR, "%s: problem writing to cld pipe (%ld): %m", -+ __func__, wsize); -+ ret = cld_pipe_open(clnt); -+ if (ret) { -+ xlog(L_FATAL, "%s: unable to reopen pipe: %d", -+ __func__, ret); -+ exit(ret); -+ } -+ } -+} -+ -+static void -+cld_remove(struct cld_client *clnt) -+{ -+ int ret; -+ ssize_t bsize, wsize; -+ struct cld_msg *cmsg = &clnt->cl_msg; -+ -+ xlog(D_GENERAL, "%s: remove client record.", __func__); -+ -+ ret = sqlite_remove_client(cmsg->cm_u.cm_name.cn_id, -+ cmsg->cm_u.cm_name.cn_len); -+ -+ cmsg->cm_status = ret ? -EREMOTEIO : ret; -+ -+ bsize = sizeof(*cmsg); -+ -+ xlog(D_GENERAL, "%s: downcall with status %d", __func__, -+ cmsg->cm_status); -+ wsize = atomicio((void *)write, clnt->cl_fd, cmsg, bsize); -+ if (wsize != bsize) { -+ xlog(L_ERROR, "%s: problem writing to cld pipe (%ld): %m", -+ __func__, wsize); -+ ret = cld_pipe_open(clnt); -+ if (ret) { -+ xlog(L_FATAL, "%s: unable to reopen pipe: %d", -+ __func__, ret); -+ exit(ret); -+ } -+ } -+} -+ -+static void -+cld_check(struct cld_client *clnt) -+{ -+ int ret; -+ ssize_t bsize, wsize; -+ struct cld_msg *cmsg = &clnt->cl_msg; -+ -+ xlog(D_GENERAL, "%s: check client record", __func__); -+ -+ ret = sqlite_check_client(cmsg->cm_u.cm_name.cn_id, -+ cmsg->cm_u.cm_name.cn_len); -+ -+ /* set up reply */ -+ cmsg->cm_status = ret ? -EACCES : ret; -+ -+ bsize = sizeof(*cmsg); -+ -+ xlog(D_GENERAL, "%s: downcall with status %d", __func__, -+ cmsg->cm_status); -+ wsize = atomicio((void *)write, clnt->cl_fd, cmsg, bsize); -+ if (wsize != bsize) { -+ xlog(L_ERROR, "%s: problem writing to cld pipe (%ld): %m", -+ __func__, wsize); -+ ret = cld_pipe_open(clnt); -+ if (ret) { -+ xlog(L_FATAL, "%s: unable to reopen pipe: %d", -+ __func__, ret); -+ exit(ret); -+ } -+ } -+} -+ -+static void -+cld_gracedone(struct cld_client *clnt) -+{ -+ int ret; -+ ssize_t bsize, wsize; -+ struct cld_msg *cmsg = &clnt->cl_msg; -+ -+ xlog(D_GENERAL, "%s: grace done. cm_gracetime=%ld", __func__, -+ cmsg->cm_u.cm_gracetime); -+ -+ ret = sqlite_remove_unreclaimed(cmsg->cm_u.cm_gracetime); -+ -+ /* set up reply: downcall with 0 status */ -+ cmsg->cm_status = ret ? -EREMOTEIO : ret; -+ -+ bsize = sizeof(*cmsg); -+ -+ xlog(D_GENERAL, "Doing downcall with status %d", cmsg->cm_status); -+ wsize = atomicio((void *)write, clnt->cl_fd, cmsg, bsize); -+ if (wsize != bsize) { -+ xlog(L_ERROR, "%s: problem writing to cld pipe (%ld): %m", -+ __func__, wsize); -+ ret = cld_pipe_open(clnt); -+ if (ret) { -+ xlog(L_FATAL, "%s: unable to reopen pipe: %d", -+ __func__, ret); -+ exit(ret); -+ } -+ } -+} -+ -+static void -+cldcb(int UNUSED(fd), short which, void *data) -+{ -+ ssize_t len; -+ struct cld_client *clnt = data; -+ struct cld_msg *cmsg = &clnt->cl_msg; -+ -+ if (which != EV_READ) -+ goto out; -+ -+ len = atomicio(read, clnt->cl_fd, cmsg, sizeof(*cmsg)); -+ if (len <= 0) { -+ xlog(L_ERROR, "%s: pipe read failed: %m", __func__); -+ cld_pipe_open(clnt); -+ goto out; -+ } -+ -+ if (cmsg->cm_vers != UPCALL_VERSION) { -+ xlog(L_ERROR, "%s: unsupported upcall version: %hu", -+ cmsg->cm_vers); -+ cld_pipe_open(clnt); -+ goto out; -+ } -+ -+ switch(cmsg->cm_cmd) { -+ case Cld_Create: -+ cld_create(clnt); -+ break; -+ case Cld_Remove: -+ cld_remove(clnt); -+ break; -+ case Cld_Check: -+ cld_check(clnt); -+ break; -+ case Cld_GraceDone: -+ cld_gracedone(clnt); -+ break; -+ default: -+ xlog(L_WARNING, "%s: command %u is not yet implemented", -+ __func__, cmsg->cm_cmd); -+ cld_not_implemented(clnt); -+ } -+out: -+ event_add(&clnt->cl_event, NULL); -+} -+ -+int -+main(int argc, char **argv) -+{ -+ char arg; -+ int rc = 0; -+ bool foreground = false; -+ char *progname; -+ char *storagedir = NULL; -+ struct cld_client clnt; -+ -+ memset(&clnt, 0, sizeof(clnt)); -+ -+ progname = strdup(basename(argv[0])); -+ if (!progname) { -+ fprintf(stderr, "%s: unable to allocate memory.\n", argv[0]); -+ return 1; -+ } -+ -+ event_init(); -+ xlog_syslog(0); -+ xlog_stderr(1); -+ -+ /* process command-line options */ -+ while ((arg = getopt_long(argc, argv, "hdFp:s:", longopts, -+ NULL)) != EOF) { -+ switch (arg) { -+ case 'd': -+ xlog_config(D_ALL, 1); -+ break; -+ case 'F': -+ foreground = true; -+ break; -+ case 'p': -+ pipepath = optarg; -+ break; -+ case 's': -+ storagedir = optarg; -+ break; -+ default: -+ usage(progname); -+ return 0; -+ } -+ } -+ -+ -+ xlog_open(progname); -+ if (!foreground) { -+ xlog_syslog(1); -+ xlog_stderr(0); -+ rc = daemon(0, 0); -+ if (rc) { -+ xlog(L_ERROR, "Unable to daemonize: %m"); -+ goto out; -+ } -+ } -+ -+ /* set up storage db */ -+ rc = sqlite_maindb_init(storagedir); -+ if (rc) { -+ xlog(L_ERROR, "Failed to open main database: %d", rc); -+ goto out; -+ } -+ -+ /* set up event handler */ -+ rc = cld_pipe_init(&clnt); -+ if (rc) -+ goto out; -+ -+ xlog(D_GENERAL, "%s: Starting event dispatch handler.", __func__); -+ rc = event_dispatch(); -+ if (rc < 0) -+ xlog(L_ERROR, "%s: event_dispatch failed: %m", __func__); -+ -+ close(clnt.cl_fd); -+ close(inotify_fd); -+out: -+ free(progname); -+ return rc; -+} -diff --git a/utils/nfsdcld/nfsdcld.man b/utils/nfsdcld/nfsdcld.man -new file mode 100644 -index 0000000..bad5f34 ---- /dev/null -+++ b/utils/nfsdcld/nfsdcld.man -@@ -0,0 +1,180 @@ -+.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.13) -+.\" -+.\" Standard preamble: -+.\" ======================================================================== -+.de Sp \" Vertical space (when we can't use .PP) -+.if t .sp .5v -+.if n .sp -+.. -+.de Vb \" Begin verbatim text -+.ft CW -+.nf -+.ne \\$1 -+.. -+.de Ve \" End verbatim text -+.ft R -+.fi -+.. -+.\" Set up some character translations and predefined strings. \*(-- will -+.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left -+.\" double quote, and \*(R" will give a right double quote. \*(C+ will -+.\" give a nicer C++. Capital omega is used to do unbreakable dashes and -+.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, -+.\" nothing in troff, for use with C<>. -+.tr \(*W- -+.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' -+.ie n \{\ -+. ds -- \(*W- -+. ds PI pi -+. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch -+. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch -+. ds L" "" -+. ds R" "" -+. ds C` "" -+. ds C' "" -+'br\} -+.el\{\ -+. ds -- \|\(em\| -+. ds PI \(*p -+. ds L" `` -+. ds R" '' -+'br\} -+.\" -+.\" Escape single quotes in literal strings from groff's Unicode transform. -+.ie \n(.g .ds Aq \(aq -+.el .ds Aq ' -+.\" -+.\" If the F register is turned on, we'll generate index entries on stderr for -+.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index -+.\" entries marked with X<> in POD. Of course, you'll have to process the -+.\" output yourself in some meaningful fashion. -+.ie \nF \{\ -+. de IX -+. tm Index:\\$1\t\\n%\t"\\$2" -+.. -+. nr % 0 -+. rr F -+.\} -+.el \{\ -+. de IX -+.. -+.\} -+.\" -+.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). -+.\" Fear. Run. Save yourself. No user-serviceable parts. -+. \" fudge factors for nroff and troff -+.if n \{\ -+. ds #H 0 -+. ds #V .8m -+. ds #F .3m -+. ds #[ \f1 -+. ds #] \fP -+.\} -+.if t \{\ -+. ds #H ((1u-(\\\\n(.fu%2u))*.13m) -+. ds #V .6m -+. ds #F 0 -+. ds #[ \& -+. ds #] \& -+.\} -+. \" simple accents for nroff and troff -+.if n \{\ -+. ds ' \& -+. ds ` \& -+. ds ^ \& -+. ds , \& -+. ds ~ ~ -+. ds / -+.\} -+.if t \{\ -+. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" -+. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' -+. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' -+. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' -+. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' -+. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' -+.\} -+. \" troff and (daisy-wheel) nroff accents -+.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' -+.ds 8 \h'\*(#H'\(*b\h'-\*(#H' -+.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] -+.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' -+.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' -+.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] -+.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] -+.ds ae a\h'-(\w'a'u*4/10)'e -+.ds Ae A\h'-(\w'A'u*4/10)'E -+. \" corrections for vroff -+.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' -+.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' -+. \" for low resolution devices (crt and lpr) -+.if \n(.H>23 .if \n(.V>19 \ -+\{\ -+. ds : e -+. ds 8 ss -+. ds o a -+. ds d- d\h'-1'\(ga -+. ds D- D\h'-1'\(hy -+. ds th \o'bp' -+. ds Th \o'LP' -+. ds ae ae -+. ds Ae AE -+.\} -+.rm #[ #] #H #V #F C -+.\" ======================================================================== -+.\" -+.IX Title "NFSDCLD 8" -+.TH NFSDCLD 8 "2011-12-21" "" "" -+.\" For nroff, turn off justification. Always turn off hyphenation; it makes -+.\" way too many mistakes in technical documents. -+.if n .ad l -+.nh -+.SH "NAME" -+nfsdcld \- NFSv4 Client Tracking Daemon -+.SH "SYNOPSIS" -+.IX Header "SYNOPSIS" -+nfsdcld [\-d] [\-F] [\-p path] [\-s stable storage dir] -+.SH "DESCRIPTION" -+.IX Header "DESCRIPTION" -+nfsdcld is the NFSv4 client tracking daemon. It is not necessary to run -+this daemon on machines that are not acting as NFSv4 servers. -+.PP -+When a network partition is combined with a server reboot, there are -+edge conditions that can cause the server to grant lock reclaims when -+other clients have taken conflicting locks in the interim. A more detailed -+explanation of this issue is described in \s-1RFC\s0 3530, section 8.6.3. -+.PP -+In order to prevent these problems, the server must track a small amount -+of per-client information on stable storage. This daemon provides the -+userspace piece of that functionality. -+.SH "OPTIONS" -+.IX Header "OPTIONS" -+.IP "\fB\-d\fR, \fB\-\-debug\fR" 4 -+.IX Item "-d, --debug" -+Enable debug level logging. -+.IP "\fB\-F\fR, \fB\-\-foreground\fR" 4 -+.IX Item "-F, --foreground" -+Runs the daemon in the foreground and prints all output to stderr -+.IP "\fB\-p\fR \fIpipe\fR, \fB\-\-pipe\fR=\fIpipe\fR" 4 -+.IX Item "-p pipe, --pipe=pipe" -+Location of the \*(L"cld\*(R" upcall pipe. The default value is -+\&\fI/var/lib/nfs/rpc_pipefs/nfsd/cld\fR. If the pipe does not exist when the -+daemon starts then it will wait for it to be created. -+.IP "\fB\-s\fR \fIstoragedir\fR, \fB\-\-storagedir\fR=\fIstorage_dir\fR" 4 -+.IX Item "-s storagedir, --storagedir=storage_dir" -+Directory where stable storage information should be kept. The default -+value is \fI/var/lib/nfs/nfsdcld\fR. -+.SH "NOTES" -+.IX Header "NOTES" -+The Linux kernel NFSv4 server has historically tracked this information -+on stable storage by manipulating information on the filesystem -+directly, in the directory to which \fI/proc/fs/nfsd/nfsv4recoverydir\fR -+points. -+.PP -+This daemon requires a kernel that supports the nfsdcld upcall. If the -+kernel does not support the new upcall, or is using the legacy client -+name tracking code then it will not create the pipe that nfsdcld uses to -+talk to the kernel. -+.SH "AUTHORS" -+.IX Header "AUTHORS" -+The nfsdcld daemon was developed by Jeff Layton . -diff --git a/utils/nfsdcld/sqlite.c b/utils/nfsdcld/sqlite.c -new file mode 100644 -index 0000000..9e35774 ---- /dev/null -+++ b/utils/nfsdcld/sqlite.c -@@ -0,0 +1,390 @@ -+/* -+ * Copyright (C) 2011 Red Hat, Jeff Layton -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version 2 -+ * of the License, or (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ */ -+ -+/* -+ * Explanation: -+ * -+ * This file contains the code to manage the sqlite backend database for the -+ * clstated upcall daemon. -+ * -+ * The main database is called main.sqlite and contains the following tables: -+ * -+ * parameters: simple key/value pairs for storing database info -+ * -+ * clients: one column containing a BLOB with the as sent by the client -+ * and a timestamp (in epoch seconds) of when the record was -+ * established -+ * -+ * FIXME: should we also record the fsid being accessed? -+ */ -+ -+#ifdef HAVE_CONFIG_H -+#include "config.h" -+#endif /* HAVE_CONFIG_H */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "xlog.h" -+ -+#define CLD_SQLITE_SCHEMA_VERSION 1 -+ -+#ifndef CLD_SQLITE_TOPDIR -+#define CLD_SQLITE_TOPDIR NFS_STATEDIR "/nfsdcld" -+#endif -+ -+/* in milliseconds */ -+#define CLD_SQLITE_BUSY_TIMEOUT 10000 -+ -+/* private data structures */ -+ -+/* global variables */ -+ -+/* top level DB directory */ -+static char *sqlite_topdir; -+ -+/* reusable pathname and sql command buffer */ -+static char buf[PATH_MAX]; -+ -+/* global database handle */ -+static sqlite3 *dbh; -+ -+/* forward declarations */ -+ -+/* make a directory, ignoring EEXIST errors unless it's not a directory */ -+static int -+mkdir_if_not_exist(char *dirname) -+{ -+ int ret; -+ struct stat statbuf; -+ -+ ret = mkdir(dirname, S_IRWXU); -+ if (ret && errno != EEXIST) -+ return -errno; -+ -+ ret = stat(dirname, &statbuf); -+ if (ret) -+ return -errno; -+ -+ if (!S_ISDIR(statbuf.st_mode)) -+ ret = -ENOTDIR; -+ -+ return ret; -+} -+ -+/* -+ * Open the "main" database, and attempt to initialize it by creating the -+ * parameters table and inserting the schema version into it. Ignore any errors -+ * from that, and then attempt to select the version out of it again. If the -+ * version appears wrong, then assume that the DB is corrupt or has been -+ * upgraded, and return an error. If all of that works, then attempt to create -+ * the "clients" table. -+ */ -+int -+sqlite_maindb_init(char *topdir) -+{ -+ int ret; -+ char *err = NULL; -+ sqlite3_stmt *stmt = NULL; -+ -+ sqlite_topdir = topdir ? topdir : CLD_SQLITE_TOPDIR; -+ -+ ret = mkdir_if_not_exist(sqlite_topdir); -+ if (ret) -+ return ret; -+ -+ ret = snprintf(buf, PATH_MAX - 1, "%s/main.sqlite", sqlite_topdir); -+ if (ret < 0) -+ return ret; -+ -+ buf[PATH_MAX - 1] = '\0'; -+ -+ ret = sqlite3_open(buf, &dbh); -+ if (ret != SQLITE_OK) { -+ xlog(L_ERROR, "Unable to open main database: %d", ret); -+ return ret; -+ } -+ -+ ret = sqlite3_busy_timeout(dbh, CLD_SQLITE_BUSY_TIMEOUT); -+ if (ret != SQLITE_OK) { -+ xlog(L_ERROR, "Unable to set sqlite busy timeout: %d", ret); -+ goto out_err; -+ } -+ -+ /* Try to create table */ -+ ret = sqlite3_exec(dbh, "CREATE TABLE IF NOT EXISTS parameters " -+ "(key TEXT PRIMARY KEY, value TEXT);", -+ NULL, NULL, &err); -+ if (ret != SQLITE_OK) { -+ xlog(L_ERROR, "Unable to create parameter table: %d", ret); -+ goto out_err; -+ } -+ -+ /* insert version into table -- ignore error if it fails */ -+ ret = snprintf(buf, sizeof(buf), -+ "INSERT OR IGNORE INTO parameters values (\"version\", " -+ "\"%d\");", CLD_SQLITE_SCHEMA_VERSION); -+ if (ret < 0) { -+ goto out_err; -+ } else if ((size_t)ret >= sizeof(buf)) { -+ ret = -EINVAL; -+ goto out_err; -+ } -+ -+ ret = sqlite3_exec(dbh, (const char *)buf, NULL, NULL, &err); -+ if (ret != SQLITE_OK) { -+ xlog(L_ERROR, "Unable to insert into parameter table: %d", -+ ret); -+ goto out_err; -+ } -+ -+ ret = sqlite3_prepare_v2(dbh, -+ "SELECT value FROM parameters WHERE key == \"version\";", -+ -1, &stmt, NULL); -+ if (ret != SQLITE_OK) { -+ xlog(L_ERROR, "Unable to prepare select statement: %d", ret); -+ goto out_err; -+ } -+ -+ /* check schema version */ -+ ret = sqlite3_step(stmt); -+ if (ret != SQLITE_ROW) { -+ xlog(L_ERROR, "Select statement execution failed: %s", -+ sqlite3_errmsg(dbh)); -+ goto out_err; -+ } -+ -+ /* process SELECT result */ -+ ret = sqlite3_column_int(stmt, 0); -+ if (ret != CLD_SQLITE_SCHEMA_VERSION) { -+ xlog(L_ERROR, "Unsupported database schema version! " -+ "Expected %d, got %d.", -+ CLD_SQLITE_SCHEMA_VERSION, ret); -+ ret = -EINVAL; -+ goto out_err; -+ } -+ -+ /* now create the "clients" table */ -+ ret = sqlite3_exec(dbh, "CREATE TABLE IF NOT EXISTS clients " -+ "(id BLOB PRIMARY KEY, time INTEGER);", -+ NULL, NULL, &err); -+ if (ret != SQLITE_OK) { -+ xlog(L_ERROR, "Unable to create clients table: %s", err); -+ goto out_err; -+ } -+ -+ sqlite3_free(err); -+ sqlite3_finalize(stmt); -+ return 0; -+ -+out_err: -+ if (err) { -+ xlog(L_ERROR, "sqlite error: %s", err); -+ sqlite3_free(err); -+ } -+ sqlite3_finalize(stmt); -+ sqlite3_close(dbh); -+ return ret; -+} -+ -+/* -+ * Create a client record -+ * -+ * Returns a non-zero sqlite error code, or SQLITE_OK (aka 0) -+ */ -+int -+sqlite_insert_client(const unsigned char *clname, const size_t namelen) -+{ -+ int ret; -+ sqlite3_stmt *stmt = NULL; -+ -+ ret = sqlite3_prepare_v2(dbh, "INSERT OR REPLACE INTO clients VALUES " -+ "(?, strftime('%s', 'now'));", -1, -+ &stmt, NULL); -+ if (ret != SQLITE_OK) { -+ xlog(L_ERROR, "%s: insert statement prepare failed: %s", -+ __func__, sqlite3_errmsg(dbh)); -+ return ret; -+ } -+ -+ ret = sqlite3_bind_blob(stmt, 1, (const void *)clname, namelen, -+ SQLITE_STATIC); -+ if (ret != SQLITE_OK) { -+ xlog(L_ERROR, "%s: bind blob failed: %s", __func__, -+ sqlite3_errmsg(dbh)); -+ goto out_err; -+ } -+ -+ ret = sqlite3_step(stmt); -+ if (ret == SQLITE_DONE) -+ ret = SQLITE_OK; -+ else -+ xlog(L_ERROR, "%s: unexpected return code from insert: %s", -+ __func__, sqlite3_errmsg(dbh)); -+ -+out_err: -+ xlog(D_GENERAL, "%s: returning %d", __func__, ret); -+ sqlite3_finalize(stmt); -+ return ret; -+} -+ -+/* Remove a client record */ -+int -+sqlite_remove_client(const unsigned char *clname, const size_t namelen) -+{ -+ int ret; -+ sqlite3_stmt *stmt = NULL; -+ -+ ret = sqlite3_prepare_v2(dbh, "DELETE FROM clients WHERE id==?", -1, -+ &stmt, NULL); -+ if (ret != SQLITE_OK) { -+ xlog(L_ERROR, "%s: statement prepare failed: %s", -+ __func__, sqlite3_errmsg(dbh)); -+ goto out_err; -+ } -+ -+ ret = sqlite3_bind_blob(stmt, 1, (const void *)clname, namelen, -+ SQLITE_STATIC); -+ if (ret != SQLITE_OK) { -+ xlog(L_ERROR, "%s: bind blob failed: %s", __func__, -+ sqlite3_errmsg(dbh)); -+ goto out_err; -+ } -+ -+ ret = sqlite3_step(stmt); -+ if (ret == SQLITE_DONE) -+ ret = SQLITE_OK; -+ else -+ xlog(L_ERROR, "%s: unexpected return code from delete: %d", -+ __func__, ret); -+ -+out_err: -+ xlog(D_GENERAL, "%s: returning %d", __func__, ret); -+ sqlite3_finalize(stmt); -+ return ret; -+} -+ -+/* -+ * Is the given clname in the clients table? If so, then update its timestamp -+ * and return success. If the record isn't present, or the update fails, then -+ * return an error. -+ */ -+int -+sqlite_check_client(const unsigned char *clname, const size_t namelen) -+{ -+ int ret; -+ sqlite3_stmt *stmt = NULL; -+ -+ ret = sqlite3_prepare_v2(dbh, "SELECT count(*) FROM clients WHERE " -+ "id==?", -1, &stmt, NULL); -+ if (ret != SQLITE_OK) { -+ xlog(L_ERROR, "%s: unable to prepare update statement: %s", -+ __func__, sqlite3_errmsg(dbh)); -+ goto out_err; -+ } -+ -+ ret = sqlite3_bind_blob(stmt, 1, (const void *)clname, namelen, -+ SQLITE_STATIC); -+ if (ret != SQLITE_OK) { -+ xlog(L_ERROR, "%s: bind blob failed: %s", -+ __func__, sqlite3_errmsg(dbh)); -+ goto out_err; -+ } -+ -+ ret = sqlite3_step(stmt); -+ if (ret != SQLITE_ROW) { -+ xlog(L_ERROR, "%s: unexpected return code from select: %d", -+ __func__, ret); -+ goto out_err; -+ } -+ -+ ret = sqlite3_column_int(stmt, 0); -+ xlog(D_GENERAL, "%s: select returned %d rows", ret); -+ if (ret != 1) { -+ ret = -EACCES; -+ goto out_err; -+ } -+ -+ sqlite3_finalize(stmt); -+ stmt = NULL; -+ ret = sqlite3_prepare_v2(dbh, "UPDATE OR FAIL clients SET " -+ "time=strftime('%s', 'now') WHERE id==?", -+ -1, &stmt, NULL); -+ if (ret != SQLITE_OK) { -+ xlog(L_ERROR, "%s: unable to prepare update statement: %s", -+ __func__, sqlite3_errmsg(dbh)); -+ goto out_err; -+ } -+ -+ ret = sqlite3_bind_blob(stmt, 1, (const void *)clname, namelen, -+ SQLITE_STATIC); -+ if (ret != SQLITE_OK) { -+ xlog(L_ERROR, "%s: bind blob failed: %s", -+ __func__, sqlite3_errmsg(dbh)); -+ goto out_err; -+ } -+ -+ ret = sqlite3_step(stmt); -+ if (ret == SQLITE_DONE) -+ ret = SQLITE_OK; -+ else -+ xlog(L_ERROR, "%s: unexpected return code from update: %s", -+ __func__, sqlite3_errmsg(dbh)); -+ -+out_err: -+ xlog(D_GENERAL, "%s: returning %d", __func__, ret); -+ sqlite3_finalize(stmt); -+ return ret; -+} -+ -+/* -+ * remove any client records that were not reclaimed since grace_start. -+ */ -+int -+sqlite_remove_unreclaimed(time_t grace_start) -+{ -+ int ret; -+ char *err = NULL; -+ -+ ret = snprintf(buf, sizeof(buf), "DELETE FROM clients WHERE time < %ld", -+ grace_start); -+ if (ret < 0) { -+ return ret; -+ } else if ((size_t)ret >= sizeof(buf)) { -+ ret = -EINVAL; -+ return ret; -+ } -+ -+ ret = sqlite3_exec(dbh, buf, NULL, NULL, &err); -+ if (ret != SQLITE_OK) -+ xlog(L_ERROR, "%s: delete failed: %s", __func__, err); -+ -+ xlog(D_GENERAL, "%s: returning %d", __func__, ret); -+ sqlite3_free(err); -+ return ret; -+} -diff --git a/utils/nfsdcld/sqlite.h b/utils/nfsdcld/sqlite.h -new file mode 100644 -index 0000000..c85e7d6 ---- /dev/null -+++ b/utils/nfsdcld/sqlite.h -@@ -0,0 +1,29 @@ -+/* -+ * Copyright (C) 2011 Red Hat, Jeff Layton -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version 2 -+ * of the License, or (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ */ -+ -+#ifndef _SQLITE_H_ -+#define _SQLITE_H_ -+ -+int sqlite_maindb_init(char *topdir); -+int sqlite_insert_client(const unsigned char *clname, const size_t namelen); -+int sqlite_remove_client(const unsigned char *clname, const size_t namelen); -+int sqlite_check_client(const unsigned char *clname, const size_t namelen); -+int sqlite_remove_unreclaimed(const time_t grace_start); -+ -+#endif /* _SQLITE_H */ -diff --git a/utils/nfsidmap/Makefile.am b/utils/nfsidmap/Makefile.am -index f837b91..c0675c4 100644 ---- a/utils/nfsidmap/Makefile.am -+++ b/utils/nfsidmap/Makefile.am -@@ -4,6 +4,6 @@ man8_MANS = nfsidmap.man - - sbin_PROGRAMS = nfsidmap - nfsidmap_SOURCES = nfsidmap.c --nfsidmap_LDADD = -lnfsidmap -lkeyutils -+nfsidmap_LDADD = $(LIBNFSIDMAP) -lkeyutils ../../support/nfs/libnfs.a - - MAINTAINERCLEANFILES = Makefile.in -diff --git a/utils/nfsidmap/nfsidmap.c b/utils/nfsidmap/nfsidmap.c -index 2d87381..cf11551 100644 ---- a/utils/nfsidmap/nfsidmap.c -+++ b/utils/nfsidmap/nfsidmap.c -@@ -3,21 +3,33 @@ - #include - #include - #include -+#include - - #include - #include - #include - #include - --#include -+#include -+#include "xlog.h" - --/* gcc nfsidmap.c -o nfsidmap -l nfsidmap -l keyutils */ -+int verbose = 0; -+char *usage="Usage: %s [-v] [-c || [-u|-g|-r key] || [-t timeout] key desc]"; - - #define MAX_ID_LEN 11 - #define IDMAP_NAMESZ 128 - #define USER 1 - #define GROUP 0 - -+#define PROCKEYS "/proc/keys" -+#ifndef DEFAULT_KEYRING -+#define DEFAULT_KEYRING "id_resolver" -+#endif -+ -+static int keyring_clear(char *keyring); -+ -+#define UIDKEYS 0x1 -+#define GIDKEYS 0x2 - - /* - * Find either a user or group id based on the name@domain string -@@ -36,9 +48,31 @@ int id_lookup(char *name_at_domain, key_serial_t key, int type) - rc = nfs4_group_owner_to_gid(name_at_domain, &gid); - sprintf(id, "%u", gid); - } -+ if (rc < 0) -+ xlog_err("id_lookup: %s: failed: %m", -+ (type == USER ? "nfs4_owner_to_uid" : "nfs4_group_owner_to_gid")); - -- if (rc == 0) -+ if (rc == 0) { - rc = keyctl_instantiate(key, id, strlen(id) + 1, 0); -+ if (rc < 0) { -+ switch(rc) { -+ case -EDQUOT: -+ case -ENFILE: -+ case -ENOMEM: -+ /* -+ * The keyring is full. Clear the keyring and try again -+ */ -+ rc = keyring_clear(DEFAULT_KEYRING); -+ if (rc == 0) -+ rc = keyctl_instantiate(key, id, strlen(id) + 1, 0); -+ break; -+ default: -+ break; -+ } -+ } -+ if (rc < 0) -+ xlog_err("id_lookup: keyctl_instantiate failed: %m"); -+ } - - return rc; - } -@@ -57,6 +91,7 @@ int name_lookup(char *id, key_serial_t key, int type) - rc = nfs4_get_default_domain(NULL, domain, NFS4_MAX_DOMAIN_LEN); - if (rc != 0) { - rc = -1; -+ xlog_err("name_lookup: nfs4_get_default_domain failed: %m"); - goto out; - } - -@@ -67,39 +102,206 @@ int name_lookup(char *id, key_serial_t key, int type) - gid = atoi(id); - rc = nfs4_gid_to_name(gid, domain, name, IDMAP_NAMESZ); - } -+ if (rc < 0) -+ xlog_err("name_lookup: %s: failed: %m", -+ (type == USER ? "nfs4_uid_to_name" : "nfs4_gid_to_name")); - -- if (rc == 0) -+ if (rc == 0) { - rc = keyctl_instantiate(key, &name, strlen(name), 0); -- -+ if (rc < 0) -+ xlog_err("name_lookup: keyctl_instantiate failed: %m"); -+ } - out: - return rc; - } -+/* -+ * Clear all the keys on the given keyring -+ */ -+static int keyring_clear(char *keyring) -+{ -+ FILE *fp; -+ char buf[BUFSIZ]; -+ key_serial_t key; -+ -+ if (keyring == NULL) -+ keyring = DEFAULT_KEYRING; -+ -+ if ((fp = fopen(PROCKEYS, "r")) == NULL) { -+ xlog_err("fopen(%s) failed: %m", PROCKEYS); -+ return 1; -+ } -+ -+ while(fgets(buf, BUFSIZ, fp) != NULL) { -+ if (strstr(buf, "keyring") == NULL) -+ continue; -+ if (strstr(buf, keyring) == NULL) -+ continue; -+ if (verbose) { -+ *(strchr(buf, '\n')) = '\0'; -+ xlog_warn("clearing '%s'", buf); -+ } -+ /* -+ * The key is the first arugment in the string -+ */ -+ *(strchr(buf, ' ')) = '\0'; -+ sscanf(buf, "%x", &key); -+ if (keyctl_clear(key) < 0) { -+ xlog_err("keyctl_clear(0x%x) failed: %m", key); -+ fclose(fp); -+ return 1; -+ } -+ fclose(fp); -+ return 0; -+ } -+ xlog_err("'%s' keyring was not found.", keyring); -+ fclose(fp); -+ return 1; -+} -+/* -+ * Revoke a key -+ */ -+static int key_revoke(char *keystr, int keymask) -+{ -+ FILE *fp; -+ char buf[BUFSIZ], *ptr; -+ key_serial_t key; -+ int mask; -+ -+ xlog_syslog(0); -+ -+ if ((fp = fopen(PROCKEYS, "r")) == NULL) { -+ xlog_err("fopen(%s) failed: %m", PROCKEYS); -+ return 1; -+ } -+ -+ while(fgets(buf, BUFSIZ, fp) != NULL) { -+ if (strstr(buf, "keyring") != NULL) -+ continue; -+ -+ mask = 0; -+ if ((ptr = strstr(buf, "uid:")) != NULL) -+ mask = UIDKEYS; -+ else if ((ptr = strstr(buf, "gid:")) != NULL) -+ mask = GIDKEYS; -+ else -+ continue; -+ -+ if ((keymask & mask) == 0) -+ continue; -+ -+ if (strncmp(ptr+4, keystr, strlen(keystr)) != 0) -+ continue; -+ -+ if (verbose) { -+ *(strchr(buf, '\n')) = '\0'; -+ xlog_warn("revoking '%s'", buf); -+ } -+ /* -+ * The key is the first arugment in the string -+ */ -+ *(strchr(buf, ' ')) = '\0'; -+ sscanf(buf, "%x", &key); -+ -+ if (keyctl_revoke(key) < 0) { -+ xlog_err("keyctl_revoke(0x%x) failed: %m", key); -+ fclose(fp); -+ return 1; -+ } -+ -+ keymask &= ~mask; -+ if (keymask == 0) { -+ fclose(fp); -+ return 0; -+ } -+ } -+ xlog_err("'%s' key was not found.", keystr); -+ fclose(fp); -+ return 1; -+} - - int main(int argc, char **argv) - { - char *arg; - char *value; - char *type; -- int rc = 1; -+ int rc = 1, opt; - int timeout = 600; - key_serial_t key; -+ char *progname, *keystr = NULL; -+ int clearing = 0, keymask = 0; -+ -+ /* Set the basename */ -+ if ((progname = strrchr(argv[0], '/')) != NULL) -+ progname++; -+ else -+ progname = argv[0]; - -- if (argc < 3) -+ xlog_open(progname); -+ -+ while ((opt = getopt(argc, argv, "u:g:r:ct:v")) != -1) { -+ switch (opt) { -+ case 'u': -+ keymask = UIDKEYS; -+ keystr = strdup(optarg); -+ break; -+ case 'g': -+ keymask = GIDKEYS; -+ keystr = strdup(optarg); -+ break; -+ case 'r': -+ keymask = GIDKEYS|UIDKEYS; -+ keystr = strdup(optarg); -+ break; -+ case 'c': -+ clearing++; -+ break; -+ case 'v': -+ verbose++; -+ break; -+ case 't': -+ timeout = atoi(optarg); -+ break; -+ default: -+ xlog_warn(usage, progname); -+ break; -+ } -+ } -+ -+ if (keystr) { -+ rc = key_revoke(keystr, keymask); -+ return rc; -+ } -+ if (clearing) { -+ xlog_syslog(0); -+ rc = keyring_clear(DEFAULT_KEYRING); -+ return rc; -+ } -+ -+ xlog_stderr(0); -+ if ((argc - optind) != 2) { -+ xlog_err("Bad arg count. Check /etc/request-key.conf"); -+ xlog_warn(usage, progname); - return 1; -+ } -+ -+ if (verbose) -+ nfs4_set_debug(verbose, NULL); -+ -+ key = strtol(argv[optind++], NULL, 10); - -- arg = malloc(sizeof(char) * strlen(argv[2]) + 1); -- strcpy(arg, argv[2]); -+ arg = strdup(argv[optind]); -+ if (arg == NULL) { -+ xlog_err("strdup failed: %m"); -+ return 1; -+ } - type = strtok(arg, ":"); - value = strtok(NULL, ":"); - -- if (argc == 4) { -- timeout = atoi(argv[3]); -- if (timeout < 0) -- timeout = 0; -+ if (verbose) { -+ xlog_warn("key: 0x%lx type: %s value: %s timeout %ld", -+ key, type, value, timeout); - } - -- key = strtol(argv[1], NULL, 10); -- - if (strcmp(type, "uid") == 0) - rc = id_lookup(value, key, USER); - else if (strcmp(type, "gid") == 0) -@@ -109,7 +311,7 @@ int main(int argc, char **argv) - else if (strcmp(type, "group") == 0) - rc = name_lookup(value, key, GROUP); - -- /* Set timeout to 5 (600 seconds) minutes */ -+ /* Set timeout to 10 (600 seconds) minutes */ - if (rc == 0) - keyctl_set_timeout(key, timeout); - -diff --git a/utils/nfsidmap/nfsidmap.man b/utils/nfsidmap/nfsidmap.man -index 2381908..3a3a523 100644 ---- a/utils/nfsidmap/nfsidmap.man -+++ b/utils/nfsidmap/nfsidmap.man -@@ -5,6 +5,12 @@ - .TH nfsidmap 5 "1 October 2010" - .SH NAME - nfsidmap \- The NFS idmapper upcall program -+.SH SYNOPSIS -+.B "nfsidmap [-v] [-t timeout] key desc" -+.br -+.B "nfsidmap [-v] [-c]" -+.br -+.B "nfsidmap [-v] [-u|-g|-r user]" - .SH DESCRIPTION - The file - .I /usr/sbin/nfsidmap -@@ -12,11 +18,36 @@ is used by the NFS idmapper to translate user and group ids into names, and to - translate user and group names into ids. Idmapper uses request-key to perform - the upcall and cache the result. - .I /usr/sbin/nfsidmap --should only be called by request-key, and will perform the translation and -+is called by /sbin/request-key, and will perform the translation and - initialize a key with the resulting information. - .PP --NFS_USE_NEW_IDMAPPER must be selected when configuring the kernel to use this --feature. -+.I nfsidmap -+can also used to clear the keyring of all the keys or -+revoke one particular key. -+This is useful when the id mappings have failed to due -+to a lookup error resulting in all the cached uids/gids to be set -+to the user id nobody. -+.SH OPTIONS -+.TP -+.B -c -+Clear the keyring of all the keys. -+.TP -+.B -g user -+Revoke the gid key of the given user. -+.TP -+.B -r user -+Revoke both the uid and gid key of the given user. -+.TP -+.B -t timeout -+Set the expiration timer, in seconds, on the key. -+The default is 600 seconds (10 mins). -+.TP -+.B -u user -+Revoke the uid key of the given user. -+.TP -+.B -v -+Increases the verbosity of the output to syslog -+(can be specified multiple times). - .SH CONFIGURING - The file - .I /etc/request-key.conf -@@ -25,11 +56,13 @@ will need to be modified so - can properly direct the upcall. The following line should be added before a call - to keyctl negate: - .PP --create id_resolver * * /usr/sbin/nfsidmap %k %d 600 -+create id_resolver * * /usr/sbin/nfsidmap -t 600 %k %d - .PP - This will direct all id_resolver requests to the program --.I /usr/sbin/nfsidmap --The last parameter, 600, defines how many seconds into the future the key will -+.I /usr/sbin/nfsidmap. -+The -+.B -t 600 -+defines how many seconds into the future the key will - expire. This is an optional parameter for - .I /usr/sbin/nfsidmap - and will default to 600 seconds when not specified. -@@ -48,9 +81,9 @@ You can choose to handle any of these individually, rather than using the - generic upcall program. If you would like to use your own program for a uid - lookup then you would edit your request-key.conf so it looks similar to this: - .PP --create id_resolver uid:* * /some/other/program %k %d 600 -+create id_resolver uid:* * /some/other/program %k %d - .br --create id_resolver * * /usr/sbin/nfsidmap %k %d 600 -+create id_resolver * * /usr/sbin/nfsidmap %k %d - .PP - Notice that the new line was added above the line for the generic program. - request-key will find the first matching line and run the corresponding program. -diff --git a/utils/osd_login/Makefile.am b/utils/osd_login/Makefile.am -new file mode 100644 -index 0000000..adc493a ---- /dev/null -+++ b/utils/osd_login/Makefile.am -@@ -0,0 +1,12 @@ -+## Process this file with automake to produce Makefile.in -+ -+OSD_LOGIN_FILES= osd_login -+ -+EXTRA_DIST= $(OSD_LOGIN_FILES) -+ -+all-local: $(OSD_LOGIN_FILES) -+ -+install-data-hook: -+ $(INSTALL) --mode 755 osd_login $(DESTDIR)/sbin/osd_login -+ -+MAINTAINERCLEANFILES = Makefile.in -diff --git a/utils/osd_login/osd_login b/utils/osd_login/osd_login -new file mode 100644 -index 0000000..08cd2d2 ---- /dev/null -+++ b/utils/osd_login/osd_login -@@ -0,0 +1,118 @@ -+#!/bin/bash -+# -+# osd_login : This script is part of the autologin feature -+# mandated by the pnfs-objects standard. -+# It is called from objlayoutdriver.ko in the kernel. -+ -+# Copyright (C) 2012, Sachin Bhamare -+# Copyright (C) 2012, Boaz Harrosh -+# -+# This program is free software; you can redistribute it and/or modify -+# it under the terms of the GNU General Public License version 2 as -+# published by the Free Software Foundation. -+# -+# This program is distributed in the hope that it will be useful, -+# but WITHOUT ANY WARRANTY; without even the implied warranty of -+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+# GNU General Public License for more details. -+# -+# You should have received a copy of the GNU General Public License -+# along with this program; if not, write to the Free Software -+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -+# MA 02110-1301 USA -+ -+umask 022 -+ -+PATH="/sbin:/usr/sbin:/bin:/usr/bin" -+ -+iscsiadm=/sbin/iscsiadm -+ -+PARENT_PID=$BASHPID -+WATCHDOG_TIMEOUT=15 -+ -+protocol="" -+portal="" -+uri="" -+osdname="" -+systemid="" -+ -+usage() -+{ -+ echo "Usage: $0 -u -o -s " -+ echo "Options:" -+ echo "-u target uri e.g. iscsi://:" -+ echo "-o osdname of the target OSD" -+ echo "-s systemid of the target OSD" -+} -+ -+parse_cmdline() -+{ -+ argc=$# -+ if [ $# -lt 3 ]; then -+ usage -+ exit 1 -+ fi -+ -+ # parse the input arguments -+ while getopts "u:o:s:" options; do -+ case $options in -+ u ) uri=$OPTARG;; -+ o ) osdname=$OPTARG;; -+ s ) systemid=$OPTARG;; -+ \? ) usage -+ exit 1;; -+ * ) usage -+ exit 1;; -+ esac -+ done -+ -+ echo "-u : $uri" -+ echo "-o : $osdname" -+ echo "-s : $systemid" -+ -+ protocol=`echo $uri | awk -F ':' '{print $1}'` -+ portal=`echo $uri | awk -F '//' '{print $2}'` -+} -+ -+watchdog() -+{ -+ timeout=$1 -+ portal=$2 -+ -+ sleep $timeout -+ if kill -9 $PARENT_PID; then -+ echo "watchdog : Timed out (>$timeout seconds) while login into $portal" | logger -t "osd_login" -+ fi -+ echo "watchdog: exiting .." -+ exit 2 -+} -+ -+login_iscsi_osd() -+{ -+ echo "login into: $1" -+ if ! $iscsiadm -m discovery -o nonpersistent -t sendtargets -p $1 --login; then -+ echo "$iscsiadm -m discovery -t sendtargets -p $1 --login returned error $? !" -+ sleep 1; -+ fi -+} -+ -+echo "============= osd_login =========" -+echo "progname : $0" -+parse_cmdline "$@" -+echo "protocol: $protocol" -+echo "portal: $portal" -+ -+watchdog $WATCHDOG_TIMEOUT $portal & -+watchdog_pid=$! -+ -+case $protocol in -+iscsi) -+ login_iscsi_osd $portal |& logger -t "osd_login" -+ ;; -+*) -+ echo "Error: protocol $protocol not supported !" | logger -t "osd_login" -+ ;; -+esac -+ -+kill -9 $watchdog_pid -+exit 0 -diff --git a/utils/showmount/Makefile.am b/utils/showmount/Makefile.am -index 077b2c7..4ba5ead 100644 ---- a/utils/showmount/Makefile.am -+++ b/utils/showmount/Makefile.am -@@ -7,7 +7,8 @@ sbin_PROGRAMS = showmount - showmount_SOURCES = showmount.c - showmount_LDADD = ../../support/export/libexport.a \ - ../../support/nfs/libnfs.a \ -- ../../support/misc/libmisc.a -+ ../../support/misc/libmisc.a \ -+ $(LIBTIRPC) - showmount_CPPFLAGS = $(AM_CPPFLAGS) $(CPPFLAGS) \ - -I$(top_builddir)/support/export - -diff --git a/utils/statd/Makefile.am b/utils/statd/Makefile.am -index 1744791..dc2bfc4 100644 ---- a/utils/statd/Makefile.am -+++ b/utils/statd/Makefile.am -@@ -15,10 +15,10 @@ BUILT_SOURCES = $(GENFILES) - statd_LDADD = ../../support/nsm/libnsm.a \ - ../../support/nfs/libnfs.a \ - ../../support/misc/libmisc.a \ -- $(LIBWRAP) $(LIBNSL) $(LIBCAP) -+ $(LIBWRAP) $(LIBNSL) $(LIBCAP) $(LIBTIRPC) - sm_notify_LDADD = ../../support/nsm/libnsm.a \ - ../../support/nfs/libnfs.a \ -- $(LIBNSL) $(LIBCAP) -+ $(LIBNSL) $(LIBCAP) $(LIBTIRPC) - - EXTRA_DIST = sim_sm_inter.x $(man8_MANS) COPYRIGHT simulate.c -