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