6522 lines
184 KiB
Diff
6522 lines
184 KiB
Diff
|
diff -up nfs-utils-1.2.2/aclocal/libcap.m4.orig nfs-utils-1.2.2/aclocal/libcap.m4
|
||
|
--- nfs-utils-1.2.2/aclocal/libcap.m4.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/aclocal/libcap.m4 2010-09-16 16:29:35.224032527 -0400
|
||
|
@@ -5,11 +5,19 @@ AC_DEFUN([AC_LIBCAP], [
|
||
|
dnl look for prctl
|
||
|
AC_CHECK_FUNC([prctl], , )
|
||
|
|
||
|
- dnl look for the library; do not add to LIBS if found
|
||
|
- AC_CHECK_LIB([cap], [cap_get_proc], [LIBCAP=-lcap], ,)
|
||
|
- AC_SUBST(LIBCAP)
|
||
|
+ AC_ARG_ENABLE([caps],
|
||
|
+ [AS_HELP_STRING([--disable-caps], [Disable capabilities support])])
|
||
|
+
|
||
|
+ LIBCAP=
|
||
|
+
|
||
|
+ if test "x$enable_caps" != "xno" ; then
|
||
|
+ dnl look for the library; do not add to LIBS if found
|
||
|
+ AC_CHECK_LIB([cap], [cap_get_proc], [LIBCAP=-lcap], ,)
|
||
|
|
||
|
- AC_CHECK_HEADERS([sys/capability.h], ,
|
||
|
- [AC_MSG_ERROR([libcap headers not found.])])
|
||
|
+ AC_CHECK_HEADERS([sys/capability.h], ,
|
||
|
+ [test "x$enable_caps" = "xyes" && AC_MSG_ERROR([libcap headers not found.])])
|
||
|
+ fi
|
||
|
+
|
||
|
+ AC_SUBST(LIBCAP)
|
||
|
|
||
|
])dnl
|
||
|
diff -up nfs-utils-1.2.2/configure.ac.orig nfs-utils-1.2.2/configure.ac
|
||
|
--- nfs-utils-1.2.2/configure.ac.orig 2010-09-16 15:40:15.598012398 -0400
|
||
|
+++ nfs-utils-1.2.2/configure.ac 2010-09-16 16:29:35.224032527 -0400
|
||
|
@@ -89,7 +89,7 @@ AC_ARG_ENABLE(nfsv41,
|
||
|
if test "$enable_nfsv41" = yes; then
|
||
|
AC_DEFINE(NFS41_SUPPORTED, 1, [Define this if you want NFSv41 support compiled in])
|
||
|
else
|
||
|
- enable_nfsv4=
|
||
|
+ enable_nfsv41=
|
||
|
fi
|
||
|
AC_SUBST(enable_nfsv41)
|
||
|
AM_CONDITIONAL(CONFIG_NFSV41, [test "$enable_nfsv41" = "yes"])
|
||
|
@@ -411,7 +411,7 @@ case $host in
|
||
|
ARCHFLAGS="" ;;
|
||
|
esac
|
||
|
|
||
|
-my_am_cflags="-Wall -Wstrict-prototypes $ARCHFLAGS -pipe"
|
||
|
+my_am_cflags="-Wall -Wextra -Wstrict-prototypes $ARCHFLAGS -pipe"
|
||
|
|
||
|
AC_SUBST([AM_CFLAGS], ["$my_am_cflags"])
|
||
|
|
||
|
@@ -436,6 +436,8 @@ AC_CONFIG_FILES([
|
||
|
tools/nlmtest/Makefile
|
||
|
tools/rpcdebug/Makefile
|
||
|
tools/rpcgen/Makefile
|
||
|
+ tools/mountstats/Makefile
|
||
|
+ tools/nfs-iostat/Makefile
|
||
|
utils/Makefile
|
||
|
utils/exportfs/Makefile
|
||
|
utils/gssd/Makefile
|
||
|
diff -up nfs-utils-1.2.2/support/export/client.c.orig nfs-utils-1.2.2/support/export/client.c
|
||
|
--- nfs-utils-1.2.2/support/export/client.c.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/support/export/client.c 2010-09-16 16:29:35.225032543 -0400
|
||
|
@@ -17,7 +17,9 @@
|
||
|
#include <string.h>
|
||
|
#include <ctype.h>
|
||
|
#include <netdb.h>
|
||
|
-#include "xmalloc.h"
|
||
|
+#include <errno.h>
|
||
|
+
|
||
|
+#include "sockaddr.h"
|
||
|
#include "misc.h"
|
||
|
#include "nfslib.h"
|
||
|
#include "exportfs.h"
|
||
|
@@ -28,58 +30,260 @@
|
||
|
#if !defined(__GLIBC__) || __GLIBC__ < 2
|
||
|
extern int innetgr(char *netgr, char *host, char *, char *);
|
||
|
#endif
|
||
|
-static void client_init(nfs_client *clp, const char *hname,
|
||
|
- struct hostent *hp);
|
||
|
-static int client_checkaddr(nfs_client *clp, struct in_addr addr);
|
||
|
+
|
||
|
+static char *add_name(char *old, const char *add);
|
||
|
|
||
|
nfs_client *clientlist[MCL_MAXTYPES] = { NULL, };
|
||
|
|
||
|
|
||
|
-/* if canonical is set, then we *know* this is already a canonical name
|
||
|
- * so hostname lookup is avoided.
|
||
|
- * This is used when reading /proc/fs/nfs/exports
|
||
|
+static void
|
||
|
+init_addrlist(nfs_client *clp, const struct addrinfo *ai)
|
||
|
+{
|
||
|
+ int i;
|
||
|
+
|
||
|
+ if (ai == NULL)
|
||
|
+ return;
|
||
|
+
|
||
|
+ for (i = 0; (ai != NULL) && (i < NFSCLNT_ADDRMAX); i++) {
|
||
|
+ set_addrlist(clp, i, ai->ai_addr);
|
||
|
+ ai = ai->ai_next;
|
||
|
+ }
|
||
|
+
|
||
|
+ clp->m_naddr = i;
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+client_free(nfs_client *clp)
|
||
|
+{
|
||
|
+ free(clp->m_hostname);
|
||
|
+ free(clp);
|
||
|
+}
|
||
|
+
|
||
|
+static int
|
||
|
+init_netmask4(nfs_client *clp, const char *slash)
|
||
|
+{
|
||
|
+ struct sockaddr_in sin = {
|
||
|
+ .sin_family = AF_INET,
|
||
|
+ };
|
||
|
+ uint32_t shift;
|
||
|
+
|
||
|
+ /*
|
||
|
+ * Decide what kind of netmask was specified. If there's
|
||
|
+ * no '/' present, assume the netmask is all ones. If
|
||
|
+ * there is a '/' and at least one '.', look for a spelled-
|
||
|
+ * out netmask. Otherwise, assume it was a prefixlen.
|
||
|
+ */
|
||
|
+ if (slash == NULL)
|
||
|
+ shift = 0;
|
||
|
+ else {
|
||
|
+ unsigned long prefixlen;
|
||
|
+
|
||
|
+ if (strchr(slash + 1, '.') != NULL) {
|
||
|
+ if (inet_pton(AF_INET, slash + 1,
|
||
|
+ &sin.sin_addr.s_addr) == 0)
|
||
|
+ goto out_badmask;
|
||
|
+ set_addrlist_in(clp, 1, &sin);
|
||
|
+ return 1;
|
||
|
+ } else {
|
||
|
+ char *endptr;
|
||
|
+
|
||
|
+ prefixlen = strtoul(slash + 1, &endptr, 10);
|
||
|
+ if (*endptr != '\0' && prefixlen != ULONG_MAX &&
|
||
|
+ errno != ERANGE)
|
||
|
+ goto out_badprefix;
|
||
|
+ }
|
||
|
+ if (prefixlen > 32)
|
||
|
+ goto out_badprefix;
|
||
|
+ shift = 32 - (uint32_t)prefixlen;
|
||
|
+ }
|
||
|
+
|
||
|
+ /*
|
||
|
+ * Now construct the full netmask bitmask in a sockaddr_in,
|
||
|
+ * and plant it in the nfs_client record.
|
||
|
+ */
|
||
|
+ sin.sin_addr.s_addr = htonl((uint32_t)~0 << shift);
|
||
|
+ set_addrlist_in(clp, 1, &sin);
|
||
|
+
|
||
|
+ return 1;
|
||
|
+
|
||
|
+out_badmask:
|
||
|
+ xlog(L_ERROR, "Invalid netmask `%s' for %s", slash + 1, clp->m_hostname);
|
||
|
+ return 0;
|
||
|
+
|
||
|
+out_badprefix:
|
||
|
+ xlog(L_ERROR, "Invalid prefix `%s' for %s", slash + 1, clp->m_hostname);
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+#ifdef IPV6_SUPPORTED
|
||
|
+static int
|
||
|
+init_netmask6(nfs_client *clp, const char *slash)
|
||
|
+{
|
||
|
+ struct sockaddr_in6 sin6 = {
|
||
|
+ .sin6_family = AF_INET6,
|
||
|
+ };
|
||
|
+ unsigned long prefixlen;
|
||
|
+ uint32_t shift;
|
||
|
+ int i;
|
||
|
+
|
||
|
+ /*
|
||
|
+ * Decide what kind of netmask was specified. If there's
|
||
|
+ * no '/' present, assume the netmask is all ones. If
|
||
|
+ * there is a '/' and at least one ':', look for a spelled-
|
||
|
+ * out netmask. Otherwise, assume it was a prefixlen.
|
||
|
+ */
|
||
|
+ if (slash == NULL)
|
||
|
+ prefixlen = 128;
|
||
|
+ else {
|
||
|
+ if (strchr(slash + 1, ':') != NULL) {
|
||
|
+ if (!inet_pton(AF_INET6, slash + 1, &sin6.sin6_addr))
|
||
|
+ goto out_badmask;
|
||
|
+ set_addrlist_in6(clp, 1, &sin6);
|
||
|
+ return 1;
|
||
|
+ } else {
|
||
|
+ char *endptr;
|
||
|
+
|
||
|
+ prefixlen = strtoul(slash + 1, &endptr, 10);
|
||
|
+ if (*endptr != '\0' && prefixlen != ULONG_MAX &&
|
||
|
+ errno != ERANGE)
|
||
|
+ goto out_badprefix;
|
||
|
+ }
|
||
|
+ if (prefixlen > 128)
|
||
|
+ goto out_badprefix;
|
||
|
+ }
|
||
|
+
|
||
|
+ /*
|
||
|
+ * Now construct the full netmask bitmask in a sockaddr_in6,
|
||
|
+ * and plant it in the nfs_client record.
|
||
|
+ */
|
||
|
+ for (i = 0; prefixlen > 32; i++) {
|
||
|
+ sin6.sin6_addr.s6_addr32[i] = 0xffffffff;
|
||
|
+ prefixlen -= 32;
|
||
|
+ }
|
||
|
+ shift = 32 - (uint32_t)prefixlen;
|
||
|
+ sin6.sin6_addr.s6_addr32[i] = htonl((uint32_t)~0 << shift);
|
||
|
+ set_addrlist_in6(clp, 1, &sin6);
|
||
|
+
|
||
|
+ return 1;
|
||
|
+
|
||
|
+out_badmask:
|
||
|
+ xlog(L_ERROR, "Invalid netmask `%s' for %s", slash + 1, clp->m_hostname);
|
||
|
+ return 0;
|
||
|
+
|
||
|
+out_badprefix:
|
||
|
+ xlog(L_ERROR, "Invalid prefix `%s' for %s", slash + 1, clp->m_hostname);
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+#else /* IPV6_SUPPORTED */
|
||
|
+static int
|
||
|
+init_netmask6(nfs_client *UNUSED(clp), const char *UNUSED(slash))
|
||
|
+{
|
||
|
+}
|
||
|
+#endif /* IPV6_SUPPORTED */
|
||
|
+
|
||
|
+/*
|
||
|
+ * Parse the network mask for M_SUBNETWORK type clients.
|
||
|
+ *
|
||
|
+ * Return TRUE if successful, or FALSE if some error occurred.
|
||
|
+ */
|
||
|
+static int
|
||
|
+init_subnetwork(nfs_client *clp)
|
||
|
+{
|
||
|
+ struct addrinfo *ai;
|
||
|
+ sa_family_t family;
|
||
|
+ int result = 0;
|
||
|
+ char *slash;
|
||
|
+
|
||
|
+ slash = strchr(clp->m_hostname, '/');
|
||
|
+ if (slash != NULL) {
|
||
|
+ *slash = '\0';
|
||
|
+ ai = host_pton(clp->m_hostname);
|
||
|
+ *slash = '/';
|
||
|
+ } else
|
||
|
+ ai = host_pton(clp->m_hostname);
|
||
|
+ if (ai == NULL) {
|
||
|
+ xlog(L_ERROR, "Invalid IP address %s", clp->m_hostname);
|
||
|
+ return result;
|
||
|
+ }
|
||
|
+
|
||
|
+ set_addrlist(clp, 0, ai->ai_addr);
|
||
|
+ family = ai->ai_addr->sa_family;
|
||
|
+
|
||
|
+ freeaddrinfo(ai);
|
||
|
+
|
||
|
+ switch (family) {
|
||
|
+ case AF_INET:
|
||
|
+ result = init_netmask4(clp, slash);
|
||
|
+ break;
|
||
|
+ case AF_INET6:
|
||
|
+ result = init_netmask6(clp, slash);
|
||
|
+ break;
|
||
|
+ default:
|
||
|
+ xlog(L_ERROR, "Unsupported address family for %s",
|
||
|
+ clp->m_hostname);
|
||
|
+ }
|
||
|
+
|
||
|
+ return result;
|
||
|
+}
|
||
|
+
|
||
|
+static int
|
||
|
+client_init(nfs_client *clp, const char *hname, const struct addrinfo *ai)
|
||
|
+{
|
||
|
+ clp->m_hostname = strdup(hname);
|
||
|
+ if (clp->m_hostname == NULL)
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ clp->m_exported = 0;
|
||
|
+ clp->m_count = 0;
|
||
|
+ clp->m_naddr = 0;
|
||
|
+
|
||
|
+ if (clp->m_type == MCL_SUBNETWORK)
|
||
|
+ return init_subnetwork(clp);
|
||
|
+
|
||
|
+ init_addrlist(clp, ai);
|
||
|
+ return 1;
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+client_add(nfs_client *clp)
|
||
|
+{
|
||
|
+ nfs_client **cpp;
|
||
|
+
|
||
|
+ cpp = &clientlist[clp->m_type];
|
||
|
+ while (*cpp != NULL)
|
||
|
+ cpp = &((*cpp)->m_next);
|
||
|
+ clp->m_next = NULL;
|
||
|
+ *cpp = clp;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * client_lookup - look for @hname in our list of cached nfs_clients
|
||
|
+ * @hname: '\0'-terminated ASCII string containing hostname to look for
|
||
|
+ * @canonical: if set, @hname is known to be canonical DNS name
|
||
|
+ *
|
||
|
+ * Returns pointer to a matching or freshly created nfs_client. NULL
|
||
|
+ * is returned if some problem occurs.
|
||
|
*/
|
||
|
nfs_client *
|
||
|
client_lookup(char *hname, int canonical)
|
||
|
{
|
||
|
nfs_client *clp = NULL;
|
||
|
int htype;
|
||
|
- struct hostent *hp = NULL;
|
||
|
+ struct addrinfo *ai = NULL;
|
||
|
|
||
|
htype = client_gettype(hname);
|
||
|
|
||
|
if (htype == MCL_FQDN && !canonical) {
|
||
|
- struct hostent *hp2;
|
||
|
- hp = gethostbyname(hname);
|
||
|
- if (hp == NULL || hp->h_addrtype != AF_INET) {
|
||
|
- xlog(L_ERROR, "%s has non-inet addr", hname);
|
||
|
- return NULL;
|
||
|
+ ai = host_addrinfo(hname);
|
||
|
+ if (!ai) {
|
||
|
+ xlog(L_ERROR, "Failed to resolve %s", hname);
|
||
|
+ goto out;
|
||
|
}
|
||
|
- /* make sure we have canonical name */
|
||
|
- hp2 = hostent_dup(hp);
|
||
|
- hp = gethostbyaddr(hp2->h_addr, hp2->h_length,
|
||
|
- hp2->h_addrtype);
|
||
|
- if (hp) {
|
||
|
- hp = hostent_dup(hp);
|
||
|
- /* but now we might not have all addresses... */
|
||
|
- if (hp2->h_addr_list[1]) {
|
||
|
- struct hostent *hp3 =
|
||
|
- gethostbyname(hp->h_name);
|
||
|
- if (hp3) {
|
||
|
- free(hp);
|
||
|
- hp = hostent_dup(hp3);
|
||
|
- }
|
||
|
- }
|
||
|
- free(hp2);
|
||
|
- } else
|
||
|
- hp = hp2;
|
||
|
-
|
||
|
- hname = (char *) hp->h_name;
|
||
|
+ hname = ai->ai_canonname;
|
||
|
|
||
|
- for (clp = clientlist[htype]; clp; clp = clp->m_next) {
|
||
|
- if (client_check(clp, hp))
|
||
|
+ for (clp = clientlist[htype]; clp; clp = clp->m_next)
|
||
|
+ if (client_check(clp, ai))
|
||
|
break;
|
||
|
- }
|
||
|
} else {
|
||
|
for (clp = clientlist[htype]; clp; clp = clp->m_next) {
|
||
|
if (strcasecmp(hname, clp->m_hostname)==0)
|
||
|
@@ -87,106 +291,60 @@ client_lookup(char *hname, int canonical
|
||
|
}
|
||
|
}
|
||
|
|
||
|
- if (!clp) {
|
||
|
- clp = (nfs_client *) xmalloc(sizeof(*clp));
|
||
|
- memset(clp, 0, sizeof(*clp));
|
||
|
+ if (clp == NULL) {
|
||
|
+ clp = calloc(1, sizeof(*clp));
|
||
|
+ if (clp == NULL)
|
||
|
+ goto out;
|
||
|
clp->m_type = htype;
|
||
|
- client_init(clp, hname, NULL);
|
||
|
+ if (!client_init(clp, hname, NULL)) {
|
||
|
+ client_free(clp);
|
||
|
+ clp = NULL;
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
client_add(clp);
|
||
|
}
|
||
|
|
||
|
- if (htype == MCL_FQDN && clp->m_naddr == 0 && hp != NULL) {
|
||
|
- char **ap = hp->h_addr_list;
|
||
|
- int i;
|
||
|
-
|
||
|
- for (i = 0; *ap && i < NFSCLNT_ADDRMAX; i++, ap++)
|
||
|
- clp->m_addrlist[i] = *(struct in_addr *)*ap;
|
||
|
- clp->m_naddr = i;
|
||
|
- }
|
||
|
-
|
||
|
- if (hp)
|
||
|
- free (hp);
|
||
|
+ if (htype == MCL_FQDN && clp->m_naddr == 0)
|
||
|
+ init_addrlist(clp, ai);
|
||
|
|
||
|
+out:
|
||
|
+ freeaddrinfo(ai);
|
||
|
return clp;
|
||
|
}
|
||
|
|
||
|
+/**
|
||
|
+ * client_dup - create a copy of an nfs_client
|
||
|
+ * @clp: pointer to nfs_client to copy
|
||
|
+ * @ai: pointer to addrinfo used to initialize the new client's addrlist
|
||
|
+ *
|
||
|
+ * Returns a dynamically allocated nfs_client if successful, or
|
||
|
+ * NULL if some problem occurs. Caller must free the returned
|
||
|
+ * nfs_client with free(3).
|
||
|
+ */
|
||
|
nfs_client *
|
||
|
-client_dup(nfs_client *clp, struct hostent *hp)
|
||
|
+client_dup(const nfs_client *clp, const struct addrinfo *ai)
|
||
|
{
|
||
|
nfs_client *new;
|
||
|
|
||
|
- new = (nfs_client *) xmalloc(sizeof(*new));
|
||
|
+ new = (nfs_client *)malloc(sizeof(*new));
|
||
|
+ if (new == NULL)
|
||
|
+ return NULL;
|
||
|
memcpy(new, clp, sizeof(*new));
|
||
|
new->m_type = MCL_FQDN;
|
||
|
new->m_hostname = NULL;
|
||
|
|
||
|
- client_init(new, (char *) hp->h_name, hp);
|
||
|
+ if (!client_init(new, ai->ai_canonname, ai)) {
|
||
|
+ client_free(new);
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
client_add(new);
|
||
|
return new;
|
||
|
}
|
||
|
|
||
|
-static void
|
||
|
-client_init(nfs_client *clp, const char *hname, struct hostent *hp)
|
||
|
-{
|
||
|
- xfree(clp->m_hostname);
|
||
|
- if (hp)
|
||
|
- clp->m_hostname = xstrdup(hp->h_name);
|
||
|
- else
|
||
|
- clp->m_hostname = xstrdup(hname);
|
||
|
-
|
||
|
- clp->m_exported = 0;
|
||
|
- clp->m_count = 0;
|
||
|
-
|
||
|
- if (clp->m_type == MCL_SUBNETWORK) {
|
||
|
- char *cp = strchr(clp->m_hostname, '/');
|
||
|
- static char slash32[] = "/32";
|
||
|
-
|
||
|
- if(!cp) cp = slash32;
|
||
|
- *cp = '\0';
|
||
|
- clp->m_addrlist[0].s_addr = inet_addr(clp->m_hostname);
|
||
|
- if (strchr(cp + 1, '.')) {
|
||
|
- clp->m_addrlist[1].s_addr = inet_addr(cp+1);
|
||
|
- }
|
||
|
- else {
|
||
|
- int netmask = atoi(cp + 1);
|
||
|
- if (0 < netmask && netmask <= 32) {
|
||
|
- clp->m_addrlist[1].s_addr =
|
||
|
- htonl ((uint32_t) ~0 << (32 - netmask));
|
||
|
- }
|
||
|
- else {
|
||
|
- xlog(L_FATAL, "invalid netmask `%s' for %s",
|
||
|
- cp + 1, clp->m_hostname);
|
||
|
- }
|
||
|
- }
|
||
|
- *cp = '/';
|
||
|
- clp->m_naddr = 0;
|
||
|
- } else if (!hp) {
|
||
|
- clp->m_naddr = 0;
|
||
|
- } else {
|
||
|
- char **ap = hp->h_addr_list;
|
||
|
- int i;
|
||
|
-
|
||
|
- for (i = 0; *ap && i < NFSCLNT_ADDRMAX; i++, ap++) {
|
||
|
- clp->m_addrlist[i] = *(struct in_addr *)*ap;
|
||
|
- }
|
||
|
- clp->m_naddr = i;
|
||
|
- }
|
||
|
-}
|
||
|
-
|
||
|
-void
|
||
|
-client_add(nfs_client *clp)
|
||
|
-{
|
||
|
- nfs_client **cpp;
|
||
|
-
|
||
|
- if (clp->m_type < 0 || clp->m_type >= MCL_MAXTYPES)
|
||
|
- xlog(L_FATAL, "unknown client type in client_add");
|
||
|
- cpp = clientlist + clp->m_type;
|
||
|
- while (*cpp)
|
||
|
- cpp = &((*cpp)->m_next);
|
||
|
- clp->m_next = NULL;
|
||
|
- *cpp = clp;
|
||
|
-}
|
||
|
-
|
||
|
+/**
|
||
|
+ * client_release - drop a reference to an nfs_client record
|
||
|
+ *
|
||
|
+ */
|
||
|
void
|
||
|
client_release(nfs_client *clp)
|
||
|
{
|
||
|
@@ -195,6 +353,10 @@ client_release(nfs_client *clp)
|
||
|
clp->m_count--;
|
||
|
}
|
||
|
|
||
|
+/**
|
||
|
+ * client_freeall - deallocate all nfs_client records
|
||
|
+ *
|
||
|
+ */
|
||
|
void
|
||
|
client_freeall(void)
|
||
|
{
|
||
|
@@ -205,57 +367,45 @@ client_freeall(void)
|
||
|
head = clientlist + i;
|
||
|
while (*head) {
|
||
|
*head = (clp = *head)->m_next;
|
||
|
- xfree(clp->m_hostname);
|
||
|
- xfree(clp);
|
||
|
+ client_free(clp);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
-nfs_client *
|
||
|
-client_find(struct hostent *hp)
|
||
|
-{
|
||
|
- nfs_client *clp;
|
||
|
- int i;
|
||
|
-
|
||
|
- for (i = 0; i < MCL_MAXTYPES; i++) {
|
||
|
- for (clp = clientlist[i]; clp; clp = clp->m_next) {
|
||
|
- if (!client_check(clp, hp))
|
||
|
- continue;
|
||
|
-#ifdef notdef
|
||
|
- if (clp->m_type == MCL_FQDN)
|
||
|
- return clp;
|
||
|
- return client_dup(clp, hp);
|
||
|
-#else
|
||
|
- return clp;
|
||
|
-#endif
|
||
|
- }
|
||
|
- }
|
||
|
- return NULL;
|
||
|
-}
|
||
|
-
|
||
|
-struct hostent *
|
||
|
-client_resolve(struct in_addr addr)
|
||
|
+/**
|
||
|
+ * client_resolve - look up an IP address
|
||
|
+ * @sap: pointer to socket address to resolve
|
||
|
+ *
|
||
|
+ * Returns an addrinfo structure, or NULL if some problem occurred.
|
||
|
+ * Caller must free the result with freeaddrinfo(3).
|
||
|
+ */
|
||
|
+struct addrinfo *
|
||
|
+client_resolve(const struct sockaddr *sap)
|
||
|
{
|
||
|
- struct hostent *he = NULL;
|
||
|
+ struct addrinfo *ai = NULL;
|
||
|
|
||
|
if (clientlist[MCL_WILDCARD] || clientlist[MCL_NETGROUP])
|
||
|
- he = get_reliable_hostbyaddr((const char*)&addr, sizeof(addr), AF_INET);
|
||
|
- if (he == NULL)
|
||
|
- he = get_hostent((const char*)&addr, sizeof(addr), AF_INET);
|
||
|
+ ai = host_reliable_addrinfo(sap);
|
||
|
+ if (ai == NULL)
|
||
|
+ ai = host_numeric_addrinfo(sap);
|
||
|
|
||
|
- return he;
|
||
|
+ return ai;
|
||
|
}
|
||
|
|
||
|
-/*
|
||
|
- * Find client name given an IP address
|
||
|
- * This is found by gathering all known names that match that IP address,
|
||
|
- * sorting them and joining them with '+'
|
||
|
+/**
|
||
|
+ * client_compose - Make a list of cached hostnames that match an IP address
|
||
|
+ * @ai: pointer to addrinfo containing IP address information to match
|
||
|
+ *
|
||
|
+ * Gather all known client hostnames that match the IP address, and sort
|
||
|
+ * the result into a comma-separated list.
|
||
|
*
|
||
|
+ * Returns a '\0'-terminated ASCII string containing a comma-separated
|
||
|
+ * sorted list of client hostnames, or NULL if no client records matched
|
||
|
+ * the IP address or memory could not be allocated. Caller must free the
|
||
|
+ * returned string with free(3).
|
||
|
*/
|
||
|
-static char *add_name(char *old, char *add);
|
||
|
-
|
||
|
char *
|
||
|
-client_compose(struct hostent *he)
|
||
|
+client_compose(const struct addrinfo *ai)
|
||
|
{
|
||
|
char *name = NULL;
|
||
|
int i;
|
||
|
@@ -263,7 +413,7 @@ client_compose(struct hostent *he)
|
||
|
for (i = 0 ; i < MCL_MAXTYPES; i++) {
|
||
|
nfs_client *clp;
|
||
|
for (clp = clientlist[i]; clp ; clp = clp->m_next) {
|
||
|
- if (!client_check(clp, he))
|
||
|
+ if (!client_check(clp, ai))
|
||
|
continue;
|
||
|
name = add_name(name, clp->m_hostname);
|
||
|
}
|
||
|
@@ -271,13 +421,19 @@ client_compose(struct hostent *he)
|
||
|
return name;
|
||
|
}
|
||
|
|
||
|
+/**
|
||
|
+ * client_member - check if @name is contained in the list @client
|
||
|
+ * @client: '\0'-terminated ASCII string containing
|
||
|
+ * comma-separated list of hostnames
|
||
|
+ * @name: '\0'-terminated ASCII string containing hostname to look for
|
||
|
+ *
|
||
|
+ * Returns 1 if @name was found in @client, otherwise zero is returned.
|
||
|
+ */
|
||
|
int
|
||
|
-client_member(char *client, char *name)
|
||
|
+client_member(const char *client, const char *name)
|
||
|
{
|
||
|
- /* check if "client" (a ',' separated list of names)
|
||
|
- * contains 'name' as a member
|
||
|
- */
|
||
|
- int l = strlen(name);
|
||
|
+ size_t l = strlen(name);
|
||
|
+
|
||
|
while (*client) {
|
||
|
if (strncmp(client, name, l) == 0 &&
|
||
|
(client[l] == ',' || client[l] == '\0'))
|
||
|
@@ -290,9 +446,8 @@ client_member(char *client, char *name)
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
-
|
||
|
-int
|
||
|
-name_cmp(char *a, char *b)
|
||
|
+static int
|
||
|
+name_cmp(const char *a, const char *b)
|
||
|
{
|
||
|
/* compare strings a and b, but only upto ',' in a */
|
||
|
while (*a && *b && *a != ',' && *a == *b)
|
||
|
@@ -305,9 +460,9 @@ name_cmp(char *a, char *b)
|
||
|
}
|
||
|
|
||
|
static char *
|
||
|
-add_name(char *old, char *add)
|
||
|
+add_name(char *old, const char *add)
|
||
|
{
|
||
|
- int len = strlen(add)+2;
|
||
|
+ size_t len = strlen(add) + 2;
|
||
|
char *new;
|
||
|
char *cp;
|
||
|
if (old) len += strlen(old);
|
||
|
@@ -340,108 +495,257 @@ add_name(char *old, char *add)
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
- * Match a host (given its hostent record) to a client record. This
|
||
|
- * is usually called from mountd.
|
||
|
+ * Check each address listed in @ai against each address
|
||
|
+ * stored in @clp. Return 1 if a match is found, otherwise
|
||
|
+ * zero.
|
||
|
*/
|
||
|
-int
|
||
|
-client_check(nfs_client *clp, struct hostent *hp)
|
||
|
+static int
|
||
|
+check_fqdn(const nfs_client *clp, const struct addrinfo *ai)
|
||
|
{
|
||
|
- char *hname = (char *) hp->h_name;
|
||
|
- char *cname = clp->m_hostname;
|
||
|
- char **ap;
|
||
|
+ int i;
|
||
|
|
||
|
- switch (clp->m_type) {
|
||
|
- case MCL_FQDN:
|
||
|
- case MCL_SUBNETWORK:
|
||
|
- for (ap = hp->h_addr_list; *ap; ap++) {
|
||
|
- if (client_checkaddr(clp, *(struct in_addr *) *ap))
|
||
|
+ for (; ai; ai = ai->ai_next)
|
||
|
+ for (i = 0; i < clp->m_naddr; i++)
|
||
|
+ if (nfs_compare_sockaddr(ai->ai_addr,
|
||
|
+ get_addrlist(clp, i)))
|
||
|
return 1;
|
||
|
- }
|
||
|
- return 0;
|
||
|
- case MCL_WILDCARD:
|
||
|
- if (wildmat(hname, cname))
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+static _Bool
|
||
|
+mask_match(const uint32_t a, const uint32_t b, const uint32_t m)
|
||
|
+{
|
||
|
+ return ((a ^ b) & m) == 0;
|
||
|
+}
|
||
|
+
|
||
|
+static int
|
||
|
+check_subnet_v4(const struct sockaddr_in *address,
|
||
|
+ const struct sockaddr_in *mask, const struct addrinfo *ai)
|
||
|
+{
|
||
|
+ for (; ai; ai = ai->ai_next) {
|
||
|
+ struct sockaddr_in *sin = (struct sockaddr_in *)ai->ai_addr;
|
||
|
+
|
||
|
+ if (sin->sin_family != AF_INET)
|
||
|
+ continue;
|
||
|
+
|
||
|
+ if (mask_match(address->sin_addr.s_addr,
|
||
|
+ sin->sin_addr.s_addr,
|
||
|
+ mask->sin_addr.s_addr))
|
||
|
return 1;
|
||
|
- else {
|
||
|
- for (ap = hp->h_aliases; *ap; ap++)
|
||
|
- if (wildmat(*ap, cname))
|
||
|
- return 1;
|
||
|
- }
|
||
|
- return 0;
|
||
|
- case MCL_NETGROUP:
|
||
|
-#ifdef HAVE_INNETGR
|
||
|
- {
|
||
|
- char *dot;
|
||
|
- int match, i;
|
||
|
- struct hostent *nhp = NULL;
|
||
|
- struct sockaddr_in addr;
|
||
|
-
|
||
|
- /* First, try to match the hostname without
|
||
|
- * splitting off the domain */
|
||
|
- if (innetgr(cname+1, hname, NULL, NULL))
|
||
|
- return 1;
|
||
|
+ }
|
||
|
+ return 0;
|
||
|
+}
|
||
|
|
||
|
- /* try the aliases as well */
|
||
|
- for (i = 0; hp->h_aliases[i]; i++) {
|
||
|
- if (innetgr(cname+1, hp->h_aliases[i], NULL, NULL))
|
||
|
- return 1;
|
||
|
- }
|
||
|
+#ifdef IPV6_SUPPORTED
|
||
|
+static int
|
||
|
+check_subnet_v6(const struct sockaddr_in6 *address,
|
||
|
+ const struct sockaddr_in6 *mask, const struct addrinfo *ai)
|
||
|
+{
|
||
|
+ for (; ai; ai = ai->ai_next) {
|
||
|
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ai->ai_addr;
|
||
|
|
||
|
- /* If hname is ip address convert to FQDN */
|
||
|
- if (inet_aton(hname, &addr.sin_addr) &&
|
||
|
- (nhp = gethostbyaddr((const char *)&(addr.sin_addr),
|
||
|
- sizeof(addr.sin_addr), AF_INET))) {
|
||
|
- hname = (char *)nhp->h_name;
|
||
|
- if (innetgr(cname+1, hname, NULL, NULL))
|
||
|
- return 1;
|
||
|
- }
|
||
|
+ if (sin6->sin6_family != AF_INET6)
|
||
|
+ continue;
|
||
|
|
||
|
- /* Okay, strip off the domain (if we have one) */
|
||
|
- if ((dot = strchr(hname, '.')) == NULL)
|
||
|
- return 0;
|
||
|
-
|
||
|
- *dot = '\0';
|
||
|
- match = innetgr(cname+1, hname, NULL, NULL);
|
||
|
- *dot = '.';
|
||
|
+ if (mask_match(address->sin6_addr.s6_addr32[0],
|
||
|
+ sin6->sin6_addr.s6_addr32[0],
|
||
|
+ mask->sin6_addr.s6_addr32[0]) &&
|
||
|
+ mask_match(address->sin6_addr.s6_addr32[1],
|
||
|
+ sin6->sin6_addr.s6_addr32[1],
|
||
|
+ mask->sin6_addr.s6_addr32[1]) &&
|
||
|
+ mask_match(address->sin6_addr.s6_addr32[2],
|
||
|
+ sin6->sin6_addr.s6_addr32[2],
|
||
|
+ mask->sin6_addr.s6_addr32[2]) &&
|
||
|
+ mask_match(address->sin6_addr.s6_addr32[3],
|
||
|
+ sin6->sin6_addr.s6_addr32[3],
|
||
|
+ mask->sin6_addr.s6_addr32[3]))
|
||
|
+ return 1;
|
||
|
+ }
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+#else /* !IPV6_SUPPORTED */
|
||
|
+static int
|
||
|
+check_subnet_v6(const struct sockaddr_in6 *UNUSED(address),
|
||
|
+ const struct sockaddr_in6 *UNUSED(mask),
|
||
|
+ const struct addrinfo *UNUSED(ai))
|
||
|
+{
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+#endif /* !IPV6_SUPPORTED */
|
||
|
|
||
|
- return match;
|
||
|
- }
|
||
|
-#else
|
||
|
- return 0;
|
||
|
-#endif
|
||
|
- case MCL_ANONYMOUS:
|
||
|
+/*
|
||
|
+ * Check each address listed in @ai against the subnetwork or
|
||
|
+ * host address stored in @clp. Return 1 if an address in @hp
|
||
|
+ * matches the host address stored in @clp, otherwise zero.
|
||
|
+ */
|
||
|
+static int
|
||
|
+check_subnetwork(const nfs_client *clp, const struct addrinfo *ai)
|
||
|
+{
|
||
|
+ switch (get_addrlist(clp, 0)->sa_family) {
|
||
|
+ case AF_INET:
|
||
|
+ return check_subnet_v4(get_addrlist_in(clp, 0),
|
||
|
+ get_addrlist_in(clp, 1), ai);
|
||
|
+ case AF_INET6:
|
||
|
+ return check_subnet_v6(get_addrlist_in6(clp, 0),
|
||
|
+ get_addrlist_in6(clp, 1), ai);
|
||
|
+ }
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+/*
|
||
|
+ * Check if a wildcard nfs_client record matches the canonical name
|
||
|
+ * or the aliases of a host. Return 1 if a match is found, otherwise
|
||
|
+ * zero.
|
||
|
+ */
|
||
|
+static int
|
||
|
+check_wildcard(const nfs_client *clp, const struct addrinfo *ai)
|
||
|
+{
|
||
|
+ char *cname = clp->m_hostname;
|
||
|
+ char *hname = ai->ai_canonname;
|
||
|
+ struct hostent *hp;
|
||
|
+ char **ap;
|
||
|
+
|
||
|
+ if (wildmat(hname, cname))
|
||
|
return 1;
|
||
|
- case MCL_GSS:
|
||
|
- return 0;
|
||
|
- default:
|
||
|
- xlog(L_FATAL, "internal: bad client type %d", clp->m_type);
|
||
|
+
|
||
|
+ /* See if hname aliases listed in /etc/hosts or nis[+]
|
||
|
+ * match the requested wildcard */
|
||
|
+ hp = gethostbyname(hname);
|
||
|
+ if (hp != NULL) {
|
||
|
+ for (ap = hp->h_aliases; *ap; ap++)
|
||
|
+ if (wildmat(*ap, cname))
|
||
|
+ return 1;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
+/*
|
||
|
+ * Check if @ai's hostname or aliases fall in a given netgroup.
|
||
|
+ * Return 1 if @ai represents a host in the netgroup, otherwise
|
||
|
+ * zero.
|
||
|
+ */
|
||
|
+#ifdef HAVE_INNETGR
|
||
|
+static int
|
||
|
+check_netgroup(const nfs_client *clp, const struct addrinfo *ai)
|
||
|
+{
|
||
|
+ const char *netgroup = clp->m_hostname + 1;
|
||
|
+ struct addrinfo *tmp = NULL;
|
||
|
+ struct hostent *hp;
|
||
|
+ char *dot, *hname;
|
||
|
+ int i, match;
|
||
|
+
|
||
|
+ match = 0;
|
||
|
+
|
||
|
+ hname = strdup(ai->ai_canonname);
|
||
|
+ if (hname == NULL) {
|
||
|
+ xlog(D_GENERAL, "%s: no memory for strdup", __func__);
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* First, try to match the hostname without
|
||
|
+ * splitting off the domain */
|
||
|
+ if (innetgr(netgroup, hname, NULL, NULL)) {
|
||
|
+ match = 1;
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* See if hname aliases listed in /etc/hosts or nis[+]
|
||
|
+ * match the requested netgroup */
|
||
|
+ hp = gethostbyname(hname);
|
||
|
+ if (hp != NULL) {
|
||
|
+ for (i = 0; hp->h_aliases[i]; i++)
|
||
|
+ if (innetgr(netgroup, hp->h_aliases[i], NULL, NULL)) {
|
||
|
+ match = 1;
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ /* If hname happens to be an IP address, convert it
|
||
|
+ * to a the canonical DNS name bound to this address. */
|
||
|
+ tmp = host_pton(hname);
|
||
|
+ if (tmp != NULL) {
|
||
|
+ char *cname = host_canonname(tmp->ai_addr);
|
||
|
+ freeaddrinfo(tmp);
|
||
|
+
|
||
|
+ /* The resulting FQDN may be in our netgroup. */
|
||
|
+ if (cname != NULL) {
|
||
|
+ free(hname);
|
||
|
+ hname = cname;
|
||
|
+ if (innetgr(netgroup, hname, NULL, NULL)) {
|
||
|
+ match = 1;
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ /* Okay, strip off the domain (if we have one) */
|
||
|
+ dot = strchr(hname, '.');
|
||
|
+ if (dot == NULL)
|
||
|
+ goto out;
|
||
|
+
|
||
|
+ *dot = '\0';
|
||
|
+ match = innetgr(netgroup, hname, NULL, NULL);
|
||
|
+
|
||
|
+out:
|
||
|
+ free(hname);
|
||
|
+ return match;
|
||
|
+}
|
||
|
+#else /* !HAVE_INNETGR */
|
||
|
static int
|
||
|
-client_checkaddr(nfs_client *clp, struct in_addr addr)
|
||
|
+check_netgroup(__attribute__((unused)) const nfs_client *clp,
|
||
|
+ __attribute__((unused)) const struct addrinfo *ai)
|
||
|
{
|
||
|
- int i;
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+#endif /* !HAVE_INNETGR */
|
||
|
|
||
|
+/**
|
||
|
+ * client_check - check if IP address information matches a cached nfs_client
|
||
|
+ * @clp: pointer to a cached nfs_client record
|
||
|
+ * @ai: pointer to addrinfo to compare it with
|
||
|
+ *
|
||
|
+ * Returns 1 if the address information matches the cached nfs_client,
|
||
|
+ * otherwise zero.
|
||
|
+ */
|
||
|
+int
|
||
|
+client_check(const nfs_client *clp, const struct addrinfo *ai)
|
||
|
+{
|
||
|
switch (clp->m_type) {
|
||
|
case MCL_FQDN:
|
||
|
- for (i = 0; i < clp->m_naddr; i++) {
|
||
|
- if (clp->m_addrlist[i].s_addr == addr.s_addr)
|
||
|
- return 1;
|
||
|
- }
|
||
|
- return 0;
|
||
|
+ return check_fqdn(clp, ai);
|
||
|
case MCL_SUBNETWORK:
|
||
|
- return !((clp->m_addrlist[0].s_addr ^ addr.s_addr)
|
||
|
- & clp->m_addrlist[1].s_addr);
|
||
|
+ return check_subnetwork(clp, ai);
|
||
|
+ case MCL_WILDCARD:
|
||
|
+ return check_wildcard(clp, ai);
|
||
|
+ case MCL_NETGROUP:
|
||
|
+ return check_netgroup(clp, ai);
|
||
|
+ case MCL_ANONYMOUS:
|
||
|
+ return 1;
|
||
|
+ case MCL_GSS:
|
||
|
+ return 0;
|
||
|
+ default:
|
||
|
+ xlog(D_GENERAL, "%s: unrecognized client type: %d",
|
||
|
+ __func__, clp->m_type);
|
||
|
}
|
||
|
+
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
+/**
|
||
|
+ * client_gettype - determine type of nfs_client given an identifier
|
||
|
+ * @ident: '\0'-terminated ASCII string containing a client identifier
|
||
|
+ *
|
||
|
+ * Returns the type of nfs_client record that would be used for
|
||
|
+ * this client.
|
||
|
+ */
|
||
|
int
|
||
|
client_gettype(char *ident)
|
||
|
{
|
||
|
- char *sp;
|
||
|
+ struct addrinfo *ai;
|
||
|
+ char *sp;
|
||
|
|
||
|
if (ident[0] == '\0' || strcmp(ident, "*")==0)
|
||
|
return MCL_ANONYMOUS;
|
||
|
@@ -461,12 +765,16 @@ client_gettype(char *ident)
|
||
|
if (*sp == '\\' && sp[1])
|
||
|
sp++;
|
||
|
}
|
||
|
- /* check for N.N.N.N */
|
||
|
- sp = ident;
|
||
|
- if(!isdigit(*sp) || strtoul(sp, &sp, 10) > 255 || *sp != '.') return MCL_FQDN;
|
||
|
- sp++; if(!isdigit(*sp) || strtoul(sp, &sp, 10) > 255 || *sp != '.') return MCL_FQDN;
|
||
|
- sp++; if(!isdigit(*sp) || strtoul(sp, &sp, 10) > 255 || *sp != '.') return MCL_FQDN;
|
||
|
- sp++; if(!isdigit(*sp) || strtoul(sp, &sp, 10) > 255 || *sp != '\0') return MCL_FQDN;
|
||
|
- /* we lie here a bit. but technically N.N.N.N == N.N.N.N/32 :) */
|
||
|
- return MCL_SUBNETWORK;
|
||
|
+
|
||
|
+ /*
|
||
|
+ * Treat unadorned IP addresses as MCL_SUBNETWORK.
|
||
|
+ * Everything else is MCL_FQDN.
|
||
|
+ */
|
||
|
+ ai = host_pton(ident);
|
||
|
+ if (ai != NULL) {
|
||
|
+ freeaddrinfo(ai);
|
||
|
+ return MCL_SUBNETWORK;
|
||
|
+ }
|
||
|
+
|
||
|
+ return MCL_FQDN;
|
||
|
}
|
||
|
diff -up nfs-utils-1.2.2/support/export/export.c.orig nfs-utils-1.2.2/support/export/export.c
|
||
|
--- nfs-utils-1.2.2/support/export/export.c.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/support/export/export.c 2010-09-16 16:29:35.226032506 -0400
|
||
|
@@ -24,9 +24,24 @@ static int export_hash(char *);
|
||
|
|
||
|
static void export_init(nfs_export *exp, nfs_client *clp,
|
||
|
struct exportent *nep);
|
||
|
-static int export_check(nfs_export *, struct hostent *, char *);
|
||
|
+static void export_add(nfs_export *exp);
|
||
|
+static int export_check(const nfs_export *exp, const struct addrinfo *ai,
|
||
|
+ const char *path);
|
||
|
static nfs_export *
|
||
|
- export_allowed_internal(struct hostent *hp, char *path);
|
||
|
+ export_allowed_internal(const struct addrinfo *ai,
|
||
|
+ const char *path);
|
||
|
+
|
||
|
+static void
|
||
|
+export_free(nfs_export *exp)
|
||
|
+{
|
||
|
+ xfree(exp->m_export.e_squids);
|
||
|
+ xfree(exp->m_export.e_sqgids);
|
||
|
+ free(exp->m_export.e_mountpoint);
|
||
|
+ free(exp->m_export.e_fslocdata);
|
||
|
+
|
||
|
+ xfree(exp->m_export.e_hostname);
|
||
|
+ xfree(exp);
|
||
|
+}
|
||
|
|
||
|
static void warn_duplicated_exports(nfs_export *exp, struct exportent *eep)
|
||
|
{
|
||
|
@@ -44,7 +59,12 @@ static void warn_duplicated_exports(nfs_
|
||
|
}
|
||
|
}
|
||
|
|
||
|
-int
|
||
|
+/**
|
||
|
+ * export_read - read entries from /etc/exports
|
||
|
+ * @fname: name of file to read from
|
||
|
+ *
|
||
|
+ */
|
||
|
+void
|
||
|
export_read(char *fname)
|
||
|
{
|
||
|
struct exportent *eep;
|
||
|
@@ -59,11 +79,15 @@ export_read(char *fname)
|
||
|
warn_duplicated_exports(exp, eep);
|
||
|
}
|
||
|
endexportent();
|
||
|
- return 0;
|
||
|
}
|
||
|
|
||
|
-/*
|
||
|
- * Create an in-core export struct from an export entry.
|
||
|
+/**
|
||
|
+ * export_create - create an in-core nfs_export record from an export entry
|
||
|
+ * @xep: export entry to lookup
|
||
|
+ * @canonical: if set, e_hostname is known to be canonical DNS name
|
||
|
+ *
|
||
|
+ * Returns a freshly instantiated export record, or NULL if
|
||
|
+ * a problem occurred.
|
||
|
*/
|
||
|
nfs_export *
|
||
|
export_create(struct exportent *xep, int canonical)
|
||
|
@@ -105,8 +129,8 @@ export_init(nfs_export *exp, nfs_client
|
||
|
* original hostname from /etc/exports, while the in-core client struct
|
||
|
* gets the newly found FQDN.
|
||
|
*/
|
||
|
-nfs_export *
|
||
|
-export_dup(nfs_export *exp, struct hostent *hp)
|
||
|
+static nfs_export *
|
||
|
+export_dup(nfs_export *exp, const struct addrinfo *ai)
|
||
|
{
|
||
|
nfs_export *new;
|
||
|
nfs_client *clp;
|
||
|
@@ -116,7 +140,11 @@ export_dup(nfs_export *exp, struct hoste
|
||
|
dupexportent(&new->m_export, &exp->m_export);
|
||
|
if (exp->m_export.e_hostname)
|
||
|
new->m_export.e_hostname = xstrdup(exp->m_export.e_hostname);
|
||
|
- clp = client_dup(exp->m_client, hp);
|
||
|
+ clp = client_dup(exp->m_client, ai);
|
||
|
+ if (clp == NULL) {
|
||
|
+ export_free(new);
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
clp->m_count++;
|
||
|
new->m_client = clp;
|
||
|
new->m_mayexport = exp->m_mayexport;
|
||
|
@@ -128,10 +156,8 @@ export_dup(nfs_export *exp, struct hoste
|
||
|
|
||
|
return new;
|
||
|
}
|
||
|
-/*
|
||
|
- * Add export entry to hash table
|
||
|
- */
|
||
|
-void
|
||
|
+
|
||
|
+static void
|
||
|
export_add(nfs_export *exp)
|
||
|
{
|
||
|
exp_hash_table *p_tbl;
|
||
|
@@ -159,19 +185,27 @@ export_add(nfs_export *exp)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
+/**
|
||
|
+ * export_find - find or create a suitable nfs_export for @ai and @path
|
||
|
+ * @ai: pointer to addrinfo for client
|
||
|
+ * @path: '\0'-terminated ASCII string containing export path
|
||
|
+ *
|
||
|
+ * Returns a pointer to nfs_export data matching @ai and @path,
|
||
|
+ * or NULL if an error occurs.
|
||
|
+ */
|
||
|
nfs_export *
|
||
|
-export_find(struct hostent *hp, char *path)
|
||
|
+export_find(const struct addrinfo *ai, const char *path)
|
||
|
{
|
||
|
nfs_export *exp;
|
||
|
int i;
|
||
|
|
||
|
for (i = 0; i < MCL_MAXTYPES; i++) {
|
||
|
for (exp = exportlist[i].p_head; exp; exp = exp->m_next) {
|
||
|
- if (!export_check(exp, hp, path))
|
||
|
+ if (!export_check(exp, ai, path))
|
||
|
continue;
|
||
|
if (exp->m_client->m_type == MCL_FQDN)
|
||
|
return exp;
|
||
|
- return export_dup(exp, hp);
|
||
|
+ return export_dup(exp, ai);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@@ -179,7 +213,7 @@ export_find(struct hostent *hp, char *pa
|
||
|
}
|
||
|
|
||
|
static nfs_export *
|
||
|
-export_allowed_internal (struct hostent *hp, char *path)
|
||
|
+export_allowed_internal(const struct addrinfo *ai, const char *path)
|
||
|
{
|
||
|
nfs_export *exp;
|
||
|
int i;
|
||
|
@@ -187,7 +221,7 @@ export_allowed_internal (struct hostent
|
||
|
for (i = 0; i < MCL_MAXTYPES; i++) {
|
||
|
for (exp = exportlist[i].p_head; exp; exp = exp->m_next) {
|
||
|
if (!exp->m_mayexport ||
|
||
|
- !export_check(exp, hp, path))
|
||
|
+ !export_check(exp, ai, path))
|
||
|
continue;
|
||
|
return exp;
|
||
|
}
|
||
|
@@ -196,8 +230,16 @@ export_allowed_internal (struct hostent
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
+/**
|
||
|
+ * export_allowed - determine if this export is allowed
|
||
|
+ * @ai: pointer to addrinfo for client
|
||
|
+ * @path: '\0'-terminated ASCII string containing export path
|
||
|
+ *
|
||
|
+ * Returns a pointer to nfs_export data matching @ai and @path,
|
||
|
+ * or NULL if the export is not allowed.
|
||
|
+ */
|
||
|
nfs_export *
|
||
|
-export_allowed(struct hostent *hp, char *path)
|
||
|
+export_allowed(const struct addrinfo *ai, const char *path)
|
||
|
{
|
||
|
nfs_export *exp;
|
||
|
char epath[MAXPATHLEN+1];
|
||
|
@@ -210,7 +252,7 @@ export_allowed(struct hostent *hp, char
|
||
|
|
||
|
/* Try the longest matching exported pathname. */
|
||
|
while (1) {
|
||
|
- exp = export_allowed_internal (hp, epath);
|
||
|
+ exp = export_allowed_internal(ai, epath);
|
||
|
if (exp)
|
||
|
return exp;
|
||
|
/* We have to treat the root, "/", specially. */
|
||
|
@@ -223,11 +265,17 @@ export_allowed(struct hostent *hp, char
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
-/*
|
||
|
- * Search hash table for export entry.
|
||
|
- */
|
||
|
+/**
|
||
|
+ * export_lookup - search hash table for export entry
|
||
|
+ * @hname: '\0'-terminated ASCII string containing client hostname to look for
|
||
|
+ * @path: '\0'-terminated ASCII string containing export path to look for
|
||
|
+ * @canonical: if set, @hname is known to be canonical DNS name
|
||
|
+ *
|
||
|
+ * Returns a pointer to nfs_export record matching @hname and @path,
|
||
|
+ * or NULL if the export was not found.
|
||
|
+ */
|
||
|
nfs_export *
|
||
|
-export_lookup(char *hname, char *path, int canonical)
|
||
|
+export_lookup(char *hname, char *path, int canonical)
|
||
|
{
|
||
|
nfs_client *clp;
|
||
|
nfs_export *exp;
|
||
|
@@ -251,14 +299,18 @@ export_lookup(char *hname, char *path, i
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
-export_check(nfs_export *exp, struct hostent *hp, char *path)
|
||
|
+export_check(const nfs_export *exp, const struct addrinfo *ai, const char *path)
|
||
|
{
|
||
|
if (strcmp(path, exp->m_export.e_path))
|
||
|
return 0;
|
||
|
|
||
|
- return client_check(exp->m_client, hp);
|
||
|
+ return client_check(exp->m_client, ai);
|
||
|
}
|
||
|
|
||
|
+/**
|
||
|
+ * export_freeall - deallocate all nfs_export records
|
||
|
+ *
|
||
|
+ */
|
||
|
void
|
||
|
export_freeall(void)
|
||
|
{
|
||
|
@@ -269,22 +321,13 @@ export_freeall(void)
|
||
|
for (exp = exportlist[i].p_head; exp; exp = nxt) {
|
||
|
nxt = exp->m_next;
|
||
|
client_release(exp->m_client);
|
||
|
- if (exp->m_export.e_squids)
|
||
|
- xfree(exp->m_export.e_squids);
|
||
|
- if (exp->m_export.e_sqgids)
|
||
|
- xfree(exp->m_export.e_sqgids);
|
||
|
- if (exp->m_export.e_mountpoint)
|
||
|
- free(exp->m_export.e_mountpoint);
|
||
|
- if (exp->m_export.e_fslocdata)
|
||
|
- xfree(exp->m_export.e_fslocdata);
|
||
|
- xfree(exp->m_export.e_hostname);
|
||
|
- xfree(exp);
|
||
|
+ export_free(exp);
|
||
|
+ }
|
||
|
+ for (j = 0; j < HASH_TABLE_SIZE; j++) {
|
||
|
+ exportlist[i].entries[j].p_first = NULL;
|
||
|
+ exportlist[i].entries[j].p_last = NULL;
|
||
|
}
|
||
|
- for(j = 0; j < HASH_TABLE_SIZE; j++) {
|
||
|
- exportlist[i].entries[j].p_first = NULL;
|
||
|
- exportlist[i].entries[j].p_last = NULL;
|
||
|
- }
|
||
|
- exportlist[i].p_head = NULL;
|
||
|
+ exportlist[i].p_head = NULL;
|
||
|
}
|
||
|
client_freeall();
|
||
|
}
|
||
|
diff -up nfs-utils-1.2.2/support/export/hostname.c.orig nfs-utils-1.2.2/support/export/hostname.c
|
||
|
--- nfs-utils-1.2.2/support/export/hostname.c.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/support/export/hostname.c 2010-09-16 16:29:35.227032188 -0400
|
||
|
@@ -1,315 +1,376 @@
|
||
|
/*
|
||
|
- * support/export/hostname.c
|
||
|
+ * Copyright 2010 Oracle. All rights reserved.
|
||
|
*
|
||
|
- * Functions for hostname.
|
||
|
+ * This file is part of nfs-utils.
|
||
|
*
|
||
|
+ * nfs-utils 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.
|
||
|
+ *
|
||
|
+ * nfs-utils 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 nfs-utils. If not, see <http://www.gnu.org/licenses/>.
|
||
|
*/
|
||
|
|
||
|
#ifdef HAVE_CONFIG_H
|
||
|
#include <config.h>
|
||
|
#endif
|
||
|
|
||
|
-/*
|
||
|
-#define TEST
|
||
|
-*/
|
||
|
-
|
||
|
#include <string.h>
|
||
|
-#include <netdb.h>
|
||
|
-#include <netinet/in.h>
|
||
|
-#include <arpa/inet.h>
|
||
|
#include <stdlib.h>
|
||
|
-#include <xlog.h>
|
||
|
-#ifdef TEST
|
||
|
-#define xmalloc malloc
|
||
|
-#else
|
||
|
-#include "xmalloc.h"
|
||
|
-#include "misc.h"
|
||
|
+#include <arpa/inet.h>
|
||
|
+#include <netdb.h>
|
||
|
+#include <errno.h>
|
||
|
+
|
||
|
+#include "sockaddr.h"
|
||
|
+#include "exportfs.h"
|
||
|
+
|
||
|
+#ifndef HAVE_DECL_AI_ADDRCONFIG
|
||
|
+#define AI_ADDRCONFIG 0
|
||
|
#endif
|
||
|
|
||
|
-#define ALIGNMENT sizeof (char *)
|
||
|
+/**
|
||
|
+ * host_ntop - generate presentation address given a sockaddr
|
||
|
+ * @sap: pointer to socket address
|
||
|
+ * @buf: working storage
|
||
|
+ * @buflen: size of @buf in bytes
|
||
|
+ *
|
||
|
+ * Returns a pointer to a @buf.
|
||
|
+ */
|
||
|
+#ifdef HAVE_GETNAMEINFO
|
||
|
+char *
|
||
|
+host_ntop(const struct sockaddr *sap, char *buf, const size_t buflen)
|
||
|
+{
|
||
|
+ socklen_t salen = nfs_sockaddr_length(sap);
|
||
|
+ int error;
|
||
|
+
|
||
|
+ memset(buf, 0, buflen);
|
||
|
+
|
||
|
+ if (salen == 0) {
|
||
|
+ (void)strncpy(buf, "bad family", buflen - 1);
|
||
|
+ return buf;
|
||
|
+ }
|
||
|
+
|
||
|
+ error = getnameinfo(sap, salen, buf, (socklen_t)buflen,
|
||
|
+ NULL, 0, NI_NUMERICHOST);
|
||
|
+ if (error != 0) {
|
||
|
+ buf[0] = '\0';
|
||
|
+ (void)strncpy(buf, "bad address", buflen - 1);
|
||
|
+ }
|
||
|
|
||
|
-static int
|
||
|
-align (int len, int al)
|
||
|
+ return buf;
|
||
|
+}
|
||
|
+#else /* !HAVE_GETNAMEINFO */
|
||
|
+char *
|
||
|
+host_ntop(const struct sockaddr *sap, char *buf, const size_t buflen)
|
||
|
{
|
||
|
- int i;
|
||
|
- i = len % al;
|
||
|
- if (i)
|
||
|
- len += al - i;
|
||
|
- return len;
|
||
|
+ const struct sockaddr_in *sin = (const struct sockaddr_in *)(char *)sap;
|
||
|
+
|
||
|
+ memset(buf, 0, buflen);
|
||
|
+
|
||
|
+ if (sin->sin_family != AF_INET)
|
||
|
+ (void)strncpy(buf, "bad family", buflen - 1);
|
||
|
+ return buf;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (inet_ntop(AF_INET, &sin->sin_addr.s_addr, buf, buflen) != NULL)
|
||
|
+ return buf;
|
||
|
+
|
||
|
+ buf[0] = '\0';
|
||
|
+ (void)strncpy(buf, "bad address", buflen - 1);
|
||
|
+ return buf;
|
||
|
}
|
||
|
+#endif /* !HAVE_GETNAMEINFO */
|
||
|
|
||
|
-struct hostent *
|
||
|
-get_hostent (const char *addr, int len, int type)
|
||
|
+/**
|
||
|
+ * host_pton - return addrinfo for a given presentation address
|
||
|
+ * @paddr: pointer to a '\0'-terminated ASCII string containing an
|
||
|
+ * IP presentation address
|
||
|
+ *
|
||
|
+ * Returns address info structure, or NULL if an error occurs. Caller
|
||
|
+ * must free the returned structure with freeaddrinfo(3).
|
||
|
+ */
|
||
|
+__attribute_malloc__
|
||
|
+struct addrinfo *
|
||
|
+host_pton(const char *paddr)
|
||
|
{
|
||
|
- struct hostent *cp;
|
||
|
- int len_ent;
|
||
|
- const char *name;
|
||
|
- int len_name;
|
||
|
- int num_aliases = 1;
|
||
|
- int len_aliases = sizeof (char *);
|
||
|
- int num_addr_list = 1;
|
||
|
- int len_addr_list = sizeof (char *);
|
||
|
- int pos;
|
||
|
- struct in_addr *ipv4;
|
||
|
-
|
||
|
- switch (type)
|
||
|
- {
|
||
|
- case AF_INET:
|
||
|
- ipv4 = (struct in_addr *) addr;
|
||
|
- name = inet_ntoa (*ipv4);
|
||
|
- break;
|
||
|
-
|
||
|
- default:
|
||
|
- return NULL;
|
||
|
- }
|
||
|
-
|
||
|
- len_ent = align (sizeof (*cp), ALIGNMENT);
|
||
|
- len_name = align (strlen (name) + 1, ALIGNMENT);
|
||
|
-
|
||
|
- num_addr_list++;
|
||
|
- len_addr_list += align (len, ALIGNMENT) + sizeof (char *);
|
||
|
-
|
||
|
- cp = (struct hostent *) xmalloc (len_ent + len_name + len_aliases
|
||
|
- + len_addr_list);
|
||
|
-
|
||
|
- cp->h_addrtype = type;
|
||
|
- cp->h_length = len;
|
||
|
- pos = len_ent;
|
||
|
- cp->h_name = (char *) &(((char *) cp) [pos]);
|
||
|
- strcpy (cp->h_name, name);
|
||
|
-
|
||
|
- pos += len_name;
|
||
|
- cp->h_aliases = (char **) &(((char *) cp) [pos]);
|
||
|
- pos += num_aliases * sizeof (char *);
|
||
|
- cp->h_aliases [0] = NULL;
|
||
|
-
|
||
|
- pos = len_ent + len_name + len_aliases;
|
||
|
- cp->h_addr_list = (char **) &(((char *) cp) [pos]);
|
||
|
- pos += num_addr_list * sizeof (char *);
|
||
|
- cp->h_addr_list [0] = (char *) &(((char *) cp) [pos]);
|
||
|
- memcpy (cp->h_addr_list [0], addr, cp->h_length);
|
||
|
- pos += align (cp->h_length, ALIGNMENT);
|
||
|
- cp->h_addr_list [1] = NULL;
|
||
|
+ struct addrinfo *ai = NULL;
|
||
|
+ struct addrinfo hint = {
|
||
|
+ /* don't return duplicates */
|
||
|
+ .ai_protocol = (int)IPPROTO_UDP,
|
||
|
+ .ai_flags = AI_NUMERICHOST,
|
||
|
+ .ai_family = AF_UNSPEC,
|
||
|
+ };
|
||
|
+ struct sockaddr_in sin;
|
||
|
+ int error, inet4;
|
||
|
+
|
||
|
+ /*
|
||
|
+ * Although getaddrinfo(3) is easier to use and supports
|
||
|
+ * IPv6, it recognizes incomplete addresses like "10.4"
|
||
|
+ * as valid AF_INET addresses. It also accepts presentation
|
||
|
+ * addresses that end with a blank.
|
||
|
+ *
|
||
|
+ * inet_pton(3) is much stricter. Use it to be certain we
|
||
|
+ * have a real AF_INET presentation address, before invoking
|
||
|
+ * getaddrinfo(3) to generate the full addrinfo list.
|
||
|
+ */
|
||
|
+ inet4 = 1;
|
||
|
+ if (inet_pton(AF_INET, paddr, &sin.sin_addr) == 0)
|
||
|
+ inet4 = 0;
|
||
|
+
|
||
|
+ error = getaddrinfo(paddr, NULL, &hint, &ai);
|
||
|
+ switch (error) {
|
||
|
+ case 0:
|
||
|
+ if (!inet4 && ai->ai_addr->sa_family == AF_INET) {
|
||
|
+ freeaddrinfo(ai);
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ return ai;
|
||
|
+ case EAI_NONAME:
|
||
|
+ if (paddr == NULL)
|
||
|
+ xlog(D_GENERAL, "%s: passed a NULL presentation address",
|
||
|
+ __func__);
|
||
|
+ break;
|
||
|
+ case EAI_SYSTEM:
|
||
|
+ xlog(D_GENERAL, "%s: failed to convert %s: (%d) %m",
|
||
|
+ __func__, paddr, errno);
|
||
|
+ break;
|
||
|
+ default:
|
||
|
+ xlog(D_GENERAL, "%s: failed to convert %s: %s",
|
||
|
+ __func__, paddr, gai_strerror(error));
|
||
|
+ break;
|
||
|
+ }
|
||
|
|
||
|
- return cp;
|
||
|
+ return NULL;
|
||
|
}
|
||
|
|
||
|
-struct hostent *
|
||
|
-hostent_dup (struct hostent *hp)
|
||
|
+/**
|
||
|
+ * host_addrinfo - return addrinfo for a given hostname
|
||
|
+ * @hostname: pointer to a '\0'-terminated ASCII string containing a hostname
|
||
|
+ *
|
||
|
+ * Returns address info structure with ai_canonname filled in, or NULL
|
||
|
+ * if no information is available for @hostname. Caller must free the
|
||
|
+ * returned structure with freeaddrinfo(3).
|
||
|
+ */
|
||
|
+__attribute_malloc__
|
||
|
+struct addrinfo *
|
||
|
+host_addrinfo(const char *hostname)
|
||
|
{
|
||
|
- int len_ent = align (sizeof (*hp), ALIGNMENT);
|
||
|
- int len_name = align (strlen (hp->h_name) + 1, ALIGNMENT);
|
||
|
- int num_aliases = 1;
|
||
|
- int len_aliases = sizeof (char *);
|
||
|
- int num_addr_list = 1;
|
||
|
- int len_addr_list = sizeof (char *);
|
||
|
- int pos, i;
|
||
|
- char **sp;
|
||
|
- struct hostent *cp;
|
||
|
-
|
||
|
- for (sp = hp->h_aliases; sp && *sp; sp++)
|
||
|
- {
|
||
|
- num_aliases++;
|
||
|
- len_aliases += align (strlen (*sp) + 1, ALIGNMENT)
|
||
|
- + sizeof (char *);
|
||
|
- }
|
||
|
-
|
||
|
- for (sp = hp->h_addr_list; *sp; sp++)
|
||
|
- {
|
||
|
- num_addr_list++;
|
||
|
- len_addr_list += align (hp->h_length, ALIGNMENT)
|
||
|
- + sizeof (char *);
|
||
|
- }
|
||
|
-
|
||
|
- cp = (struct hostent *) xmalloc (len_ent + len_name + len_aliases
|
||
|
- + len_addr_list);
|
||
|
-
|
||
|
- *cp = *hp;
|
||
|
- pos = len_ent;
|
||
|
- cp->h_name = (char *) &(((char *) cp) [pos]);
|
||
|
- strcpy (cp->h_name, hp->h_name);
|
||
|
-
|
||
|
- pos += len_name;
|
||
|
- cp->h_aliases = (char **) &(((char *) cp) [pos]);
|
||
|
- pos += num_aliases * sizeof (char *);
|
||
|
- for (sp = hp->h_aliases, i = 0; i < num_aliases; i++, sp++)
|
||
|
- if (sp && *sp)
|
||
|
- {
|
||
|
- cp->h_aliases [i] = (char *) &(((char *) cp) [pos]);
|
||
|
- strcpy (cp->h_aliases [i], *sp);
|
||
|
- pos += align (strlen (*sp) + 1, ALIGNMENT);
|
||
|
- }
|
||
|
- else
|
||
|
- cp->h_aliases [i] = NULL;
|
||
|
-
|
||
|
- pos = len_ent + len_name + len_aliases;
|
||
|
- cp->h_addr_list = (char **) &(((char *) cp) [pos]);
|
||
|
- pos += num_addr_list * sizeof (char *);
|
||
|
- for (sp = hp->h_addr_list, i = 0; i < num_addr_list; i++, sp++)
|
||
|
- if (*sp)
|
||
|
- {
|
||
|
- cp->h_addr_list [i] = (char *) &(((char *) cp) [pos]);
|
||
|
- memcpy (cp->h_addr_list [i], *sp, hp->h_length);
|
||
|
- pos += align (hp->h_length, ALIGNMENT);
|
||
|
- }
|
||
|
- else
|
||
|
- cp->h_addr_list [i] = *sp;
|
||
|
+ struct addrinfo *ai = NULL;
|
||
|
+ struct addrinfo hint = {
|
||
|
+#ifdef IPV6_SUPPORTED
|
||
|
+ .ai_family = AF_UNSPEC,
|
||
|
+#else
|
||
|
+ .ai_family = AF_INET,
|
||
|
+#endif
|
||
|
+ /* don't return duplicates */
|
||
|
+ .ai_protocol = (int)IPPROTO_UDP,
|
||
|
+ .ai_flags = AI_ADDRCONFIG | AI_CANONNAME,
|
||
|
+ };
|
||
|
+ int error;
|
||
|
+
|
||
|
+ error = getaddrinfo(hostname, NULL, &hint, &ai);
|
||
|
+ switch (error) {
|
||
|
+ case 0:
|
||
|
+ return ai;
|
||
|
+ case EAI_SYSTEM:
|
||
|
+ xlog(D_GENERAL, "%s: failed to resolve %s: (%d) %m",
|
||
|
+ __func__, hostname, errno);
|
||
|
+ break;
|
||
|
+ default:
|
||
|
+ xlog(D_GENERAL, "%s: failed to resolve %s: %s",
|
||
|
+ __func__, hostname, gai_strerror(error));
|
||
|
+ break;
|
||
|
+ }
|
||
|
|
||
|
- return cp;
|
||
|
+ return NULL;
|
||
|
}
|
||
|
|
||
|
-static int
|
||
|
-is_hostname(const char *sp)
|
||
|
+/**
|
||
|
+ * host_canonname - return canonical hostname bound to an address
|
||
|
+ * @sap: pointer to socket address to look up
|
||
|
+ *
|
||
|
+ * Discover the canonical hostname associated with the given socket
|
||
|
+ * address. The host's reverse mapping is verified in the process.
|
||
|
+ *
|
||
|
+ * Returns a '\0'-terminated ASCII string containing a hostname, or
|
||
|
+ * NULL if no hostname can be found for @sap. Caller must free
|
||
|
+ * the string.
|
||
|
+ */
|
||
|
+#ifdef HAVE_GETNAMEINFO
|
||
|
+__attribute_malloc__
|
||
|
+char *
|
||
|
+host_canonname(const struct sockaddr *sap)
|
||
|
{
|
||
|
- if (*sp == '\0' || *sp == '@')
|
||
|
- return 0;
|
||
|
+ socklen_t salen = nfs_sockaddr_length(sap);
|
||
|
+ char buf[NI_MAXHOST];
|
||
|
+ int error;
|
||
|
+
|
||
|
+ if (salen == 0) {
|
||
|
+ xlog(D_GENERAL, "%s: unsupported address family %d",
|
||
|
+ __func__, sap->sa_family);
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
|
||
|
- for (; *sp; sp++)
|
||
|
- {
|
||
|
- if (*sp == '*' || *sp == '?' || *sp == '[' || *sp == '/')
|
||
|
- return 0;
|
||
|
- if (*sp == '\\' && sp[1])
|
||
|
- sp++;
|
||
|
- }
|
||
|
+ memset(buf, 0, sizeof(buf));
|
||
|
+ error = getnameinfo(sap, salen, buf, (socklen_t)sizeof(buf),
|
||
|
+ NULL, 0, NI_NAMEREQD);
|
||
|
+ switch (error) {
|
||
|
+ case 0:
|
||
|
+ break;
|
||
|
+ case EAI_SYSTEM:
|
||
|
+ xlog(D_GENERAL, "%s: getnameinfo(3) failed: (%d) %m",
|
||
|
+ __func__, errno);
|
||
|
+ return NULL;
|
||
|
+ default:
|
||
|
+ (void)getnameinfo(sap, salen, buf, (socklen_t)sizeof(buf),
|
||
|
+ NULL, 0, NI_NUMERICHOST);
|
||
|
+ xlog(D_GENERAL, "%s: failed to resolve %s: %s",
|
||
|
+ __func__, buf, gai_strerror(error));
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
|
||
|
- return 1;
|
||
|
+ return strdup(buf);
|
||
|
}
|
||
|
-
|
||
|
-int
|
||
|
-matchhostname (const char *h1, const char *h2)
|
||
|
+#else /* !HAVE_GETNAMEINFO */
|
||
|
+__attribute_malloc__
|
||
|
+char *
|
||
|
+host_canonname(const struct sockaddr *sap)
|
||
|
{
|
||
|
- struct hostent *hp1, *hp2;
|
||
|
- int status;
|
||
|
+ const struct sockaddr_in *sin = (const struct sockaddr_in *)(char *)sap;
|
||
|
+ const struct in_addr *addr = &sin->sin_addr;
|
||
|
+ struct hostent *hp;
|
||
|
|
||
|
- if (strcasecmp (h1, h2) == 0)
|
||
|
- return 1;
|
||
|
-
|
||
|
- if (!is_hostname (h1) || !is_hostname (h2))
|
||
|
- return 0;
|
||
|
+ if (sap->sa_family != AF_INET)
|
||
|
+ return NULL;
|
||
|
|
||
|
- hp1 = gethostbyname (h1);
|
||
|
- if (hp1 == NULL)
|
||
|
- return 0;
|
||
|
-
|
||
|
- hp1 = hostent_dup (hp1);
|
||
|
-
|
||
|
- hp2 = gethostbyname (h2);
|
||
|
- if (hp2)
|
||
|
- {
|
||
|
- if (strcasecmp (hp1->h_name, hp2->h_name) == 0)
|
||
|
- status = 1;
|
||
|
- else
|
||
|
- {
|
||
|
- char **ap1, **ap2;
|
||
|
-
|
||
|
- status = 0;
|
||
|
- for (ap1 = hp1->h_addr_list; *ap1 && status == 0; ap1++)
|
||
|
- for (ap2 = hp2->h_addr_list; *ap2; ap2++)
|
||
|
- if (memcmp (*ap1, *ap2, sizeof (struct in_addr)) == 0)
|
||
|
- {
|
||
|
- status = 1;
|
||
|
- break;
|
||
|
- }
|
||
|
- }
|
||
|
- }
|
||
|
- else
|
||
|
- status = 0;
|
||
|
+ hp = gethostbyaddr(addr, (socklen_t)sizeof(addr), AF_INET);
|
||
|
+ if (hp == NULL)
|
||
|
+ return NULL;
|
||
|
|
||
|
- free (hp1);
|
||
|
- return status;
|
||
|
+ return strdup(hp->h_name);
|
||
|
}
|
||
|
+#endif /* !HAVE_GETNAMEINFO */
|
||
|
|
||
|
-
|
||
|
-/* Map IP to hostname, and then map back to addr to make sure it is a
|
||
|
- * reliable hostname
|
||
|
+/**
|
||
|
+ * host_reliable_addrinfo - return addrinfo for a given address
|
||
|
+ * @sap: pointer to socket address to look up
|
||
|
+ *
|
||
|
+ * Reverse and forward lookups are performed to ensure the address has
|
||
|
+ * proper forward and reverse mappings.
|
||
|
+ *
|
||
|
+ * Returns address info structure with ai_canonname filled in, or NULL
|
||
|
+ * if no information is available for @sap. Caller must free the returned
|
||
|
+ * structure with freeaddrinfo(3).
|
||
|
*/
|
||
|
-struct hostent *
|
||
|
-get_reliable_hostbyaddr(const char *addr, int len, int type)
|
||
|
+__attribute_malloc__
|
||
|
+struct addrinfo *
|
||
|
+host_reliable_addrinfo(const struct sockaddr *sap)
|
||
|
{
|
||
|
- struct hostent *hp = NULL;
|
||
|
+ struct addrinfo *ai;
|
||
|
+ char *hostname;
|
||
|
|
||
|
- struct hostent *reverse;
|
||
|
- struct hostent *forward;
|
||
|
- char **sp;
|
||
|
-
|
||
|
- reverse = gethostbyaddr (addr, len, type);
|
||
|
- if (!reverse)
|
||
|
+ hostname = host_canonname(sap);
|
||
|
+ if (hostname == NULL)
|
||
|
return NULL;
|
||
|
|
||
|
- /* must make sure the hostent is authorative. */
|
||
|
+ ai = host_addrinfo(hostname);
|
||
|
|
||
|
- reverse = hostent_dup (reverse);
|
||
|
- forward = gethostbyname (reverse->h_name);
|
||
|
+ free(hostname);
|
||
|
+ return ai;
|
||
|
+}
|
||
|
|
||
|
- if (forward) {
|
||
|
- /* now make sure the "addr" is in the list */
|
||
|
- for (sp = forward->h_addr_list ; *sp ; sp++) {
|
||
|
- if (memcmp (*sp, addr, forward->h_length) == 0)
|
||
|
- break;
|
||
|
- }
|
||
|
+/**
|
||
|
+ * host_numeric_addrinfo - return addrinfo without doing DNS queries
|
||
|
+ * @sap: pointer to socket address
|
||
|
+ *
|
||
|
+ * Returns address info structure, or NULL if an error occurred.
|
||
|
+ * Caller must free the returned structure with freeaddrinfo(3).
|
||
|
+ */
|
||
|
+#ifdef HAVE_GETNAMEINFO
|
||
|
+__attribute_malloc__
|
||
|
+struct addrinfo *
|
||
|
+host_numeric_addrinfo(const struct sockaddr *sap)
|
||
|
+{
|
||
|
+ socklen_t salen = nfs_sockaddr_length(sap);
|
||
|
+ char buf[INET6_ADDRSTRLEN];
|
||
|
+ struct addrinfo *ai;
|
||
|
+ int error;
|
||
|
+
|
||
|
+ if (salen == 0) {
|
||
|
+ xlog(D_GENERAL, "%s: unsupported address family %d",
|
||
|
+ __func__, sap->sa_family);
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
|
||
|
- if (*sp) {
|
||
|
- /* it's valid */
|
||
|
- hp = hostent_dup (forward);
|
||
|
- }
|
||
|
- else {
|
||
|
- /* it was a FAKE */
|
||
|
- xlog (L_WARNING, "Fake hostname %s for %s - forward lookup doesn't match reverse",
|
||
|
- reverse->h_name, inet_ntoa(*(struct in_addr*)addr));
|
||
|
- }
|
||
|
+ memset(buf, 0, sizeof(buf));
|
||
|
+ error = getnameinfo(sap, salen, buf, (socklen_t)sizeof(buf),
|
||
|
+ NULL, 0, NI_NUMERICHOST);
|
||
|
+ switch (error) {
|
||
|
+ case 0:
|
||
|
+ break;
|
||
|
+ case EAI_SYSTEM:
|
||
|
+ xlog(D_GENERAL, "%s: getnameinfo(3) failed: (%d) %m",
|
||
|
+ __func__, errno);
|
||
|
+ return NULL;
|
||
|
+ default:
|
||
|
+ xlog(D_GENERAL, "%s: getnameinfo(3) failed: %s",
|
||
|
+ __func__, gai_strerror(error));
|
||
|
+ return NULL;
|
||
|
}
|
||
|
- else {
|
||
|
- /* never heard of it. misconfigured DNS? */
|
||
|
- xlog (L_WARNING, "Fake hostname %s for %s - forward lookup doesn't exist",
|
||
|
- reverse->h_name, inet_ntoa(*(struct in_addr*)addr));
|
||
|
+
|
||
|
+ ai = host_pton(buf);
|
||
|
+
|
||
|
+ /*
|
||
|
+ * getaddrinfo(AI_NUMERICHOST) never fills in ai_canonname
|
||
|
+ */
|
||
|
+ if (ai != NULL) {
|
||
|
+ free(ai->ai_canonname); /* just in case */
|
||
|
+ ai->ai_canonname = strdup(buf);
|
||
|
+ if (ai->ai_canonname == NULL) {
|
||
|
+ freeaddrinfo(ai);
|
||
|
+ ai = NULL;
|
||
|
+ }
|
||
|
}
|
||
|
|
||
|
- free (reverse);
|
||
|
- return hp;
|
||
|
+ return ai;
|
||
|
}
|
||
|
+#else /* !HAVE_GETNAMEINFO */
|
||
|
+__attribute_malloc__
|
||
|
+struct addrinfo *
|
||
|
+host_numeric_addrinfo(const struct sockaddr *sap)
|
||
|
+{
|
||
|
+ const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;
|
||
|
+ const struct in_addr *addr = &sin->sin_addr;
|
||
|
+ char buf[INET_ADDRSTRLEN];
|
||
|
+ struct addrinfo *ai;
|
||
|
|
||
|
+ if (sap->sa_family != AF_INET)
|
||
|
+ return NULL;
|
||
|
|
||
|
-#ifdef TEST
|
||
|
-void
|
||
|
-print_host (struct hostent *hp)
|
||
|
-{
|
||
|
- char **sp;
|
||
|
+ memset(buf, 0, sizeof(buf));
|
||
|
+ if (inet_ntop(AF_INET, (char *)addr, buf,
|
||
|
+ (socklen_t)sizeof(buf)) == NULL)
|
||
|
+ return NULL;
|
||
|
|
||
|
- if (hp)
|
||
|
- {
|
||
|
- printf ("official hostname: %s\n", hp->h_name);
|
||
|
- printf ("aliases:\n");
|
||
|
- for (sp = hp->h_aliases; *sp; sp++)
|
||
|
- printf (" %s\n", *sp);
|
||
|
- printf ("IP addresses:\n");
|
||
|
- for (sp = hp->h_addr_list; *sp; sp++)
|
||
|
- printf (" %s\n", inet_ntoa (*(struct in_addr *) *sp));
|
||
|
- }
|
||
|
- else
|
||
|
- printf ("Not host information\n");
|
||
|
-}
|
||
|
+ ai = host_pton(buf);
|
||
|
|
||
|
-int
|
||
|
-main (int argc, char **argv)
|
||
|
-{
|
||
|
- struct hostent *hp = gethostbyname (argv [1]);
|
||
|
- struct hostent *cp;
|
||
|
- struct in_addr addr;
|
||
|
-
|
||
|
- print_host (hp);
|
||
|
-
|
||
|
- if (hp)
|
||
|
- {
|
||
|
- cp = hostent_dup (hp);
|
||
|
- print_host (cp);
|
||
|
- free (cp);
|
||
|
- }
|
||
|
- printf ("127.0.0.1 == %s: %d\n", argv [1],
|
||
|
- matchhostname ("127.0.0.1", argv [1]));
|
||
|
- addr.s_addr = inet_addr(argv [2]);
|
||
|
- printf ("%s\n", inet_ntoa (addr));
|
||
|
- cp = get_hostent ((const char *)&addr, sizeof(addr), AF_INET);
|
||
|
- print_host (cp);
|
||
|
- return 0;
|
||
|
+ /*
|
||
|
+ * getaddrinfo(AI_NUMERICHOST) never fills in ai_canonname
|
||
|
+ */
|
||
|
+ if (ai != NULL) {
|
||
|
+ ai->ai_canonname = strdup(buf);
|
||
|
+ if (ai->ai_canonname == NULL) {
|
||
|
+ freeaddrinfo(ai);
|
||
|
+ ai = NULL;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ return ai;
|
||
|
}
|
||
|
-#endif
|
||
|
+#endif /* !HAVE_GETNAMEINFO */
|
||
|
diff -up nfs-utils-1.2.2/support/export/nfsctl.c.orig nfs-utils-1.2.2/support/export/nfsctl.c
|
||
|
--- nfs-utils-1.2.2/support/export/nfsctl.c.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/support/export/nfsctl.c 2010-09-16 16:29:35.228032467 -0400
|
||
|
@@ -66,7 +66,7 @@ str_tolower(char *s)
|
||
|
static int
|
||
|
cltsetup(struct nfsctl_client *cltarg, nfs_client *clp)
|
||
|
{
|
||
|
- int i;
|
||
|
+ int i, j;
|
||
|
|
||
|
if (clp->m_type != MCL_FQDN) {
|
||
|
xlog(L_ERROR, "internal: can't export non-FQDN host");
|
||
|
@@ -76,10 +76,19 @@ cltsetup(struct nfsctl_client *cltarg, n
|
||
|
strncpy(cltarg->cl_ident, clp->m_hostname,
|
||
|
sizeof (cltarg->cl_ident) - 1);
|
||
|
str_tolower(cltarg->cl_ident);
|
||
|
- cltarg->cl_naddr = clp->m_naddr;
|
||
|
- for (i = 0; i < cltarg->cl_naddr && i < NFSCLNT_ADDRMAX; i++)
|
||
|
- cltarg->cl_addrlist[i] = clp->m_addrlist[i];
|
||
|
|
||
|
+ j = 0;
|
||
|
+ for (i = 0; i < cltarg->cl_naddr && i < NFSCLNT_ADDRMAX; i++) {
|
||
|
+ const struct sockaddr_in *sin = get_addrlist_in(clp, i);
|
||
|
+ if (sin->sin_family == AF_INET)
|
||
|
+ cltarg->cl_addrlist[j++] = sin->sin_addr;
|
||
|
+ }
|
||
|
+ if (j == 0) {
|
||
|
+ xlog(L_ERROR, "internal: no supported addresses in nfs_client");
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+
|
||
|
+ cltarg->cl_naddr = j;
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
@@ -100,7 +109,7 @@ expsetup(struct nfsctl_export *exparg, n
|
||
|
str_tolower(exparg->ex_client);
|
||
|
exparg->ex_flags = exp->m_export.e_flags;
|
||
|
exparg->ex_dev = (!unexport && (exp->m_export.e_flags & NFSEXP_FSID)) ?
|
||
|
- exp->m_export.e_fsid : stb.st_dev;
|
||
|
+ (__nfsd_dev_t)exp->m_export.e_fsid : stb.st_dev;
|
||
|
exparg->ex_ino = stb.st_ino;
|
||
|
exparg->ex_anon_uid = exp->m_export.e_anonuid;
|
||
|
exparg->ex_anon_gid = exp->m_export.e_anongid;
|
||
|
diff -up nfs-utils-1.2.2/support/export/rmtab.c.orig nfs-utils-1.2.2/support/export/rmtab.c
|
||
|
--- nfs-utils-1.2.2/support/export/rmtab.c.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/support/export/rmtab.c 2010-09-16 16:29:35.228032467 -0400
|
||
|
@@ -19,39 +19,54 @@
|
||
|
#include "xio.h"
|
||
|
#include "xlog.h"
|
||
|
|
||
|
+/*
|
||
|
+ * See if the entry already exists. If not,
|
||
|
+ * this was an instantiated wild card, and we
|
||
|
+ * must add it.
|
||
|
+ */
|
||
|
+static void
|
||
|
+rmtab_read_wildcard(struct rmtabent *rep)
|
||
|
+{
|
||
|
+ nfs_export *exp, *exp2;
|
||
|
+ struct addrinfo *ai;
|
||
|
+
|
||
|
+ ai = host_addrinfo(rep->r_client);
|
||
|
+ if (ai == NULL)
|
||
|
+ return;
|
||
|
+
|
||
|
+ exp = export_allowed(ai, rep->r_path);
|
||
|
+ freeaddrinfo(ai);
|
||
|
+ if (exp == NULL)
|
||
|
+ return;
|
||
|
+
|
||
|
+ exp2 = export_lookup(rep->r_client, exp->m_export.e_path, 0);
|
||
|
+ if (exp2 == NULL) {
|
||
|
+ struct exportent ee;
|
||
|
+
|
||
|
+ memset(&ee, 0, sizeof(ee));
|
||
|
+ dupexportent(&ee, &exp->m_export);
|
||
|
+
|
||
|
+ ee.e_hostname = rep->r_client;
|
||
|
+ exp2 = export_create(&ee, 0);
|
||
|
+ exp2->m_changed = exp->m_changed;
|
||
|
+ }
|
||
|
+ exp2->m_mayexport = 1;
|
||
|
+}
|
||
|
+
|
||
|
int
|
||
|
rmtab_read(void)
|
||
|
{
|
||
|
struct rmtabent *rep;
|
||
|
- nfs_export *exp = NULL;
|
||
|
|
||
|
setrmtabent("r");
|
||
|
while ((rep = getrmtabent(1, NULL)) != NULL) {
|
||
|
- struct hostent *hp = NULL;
|
||
|
int htype;
|
||
|
-
|
||
|
+
|
||
|
htype = client_gettype(rep->r_client);
|
||
|
- if ((htype == MCL_FQDN || htype == MCL_SUBNETWORK)
|
||
|
- && (hp = gethostbyname (rep->r_client))
|
||
|
- && (hp = hostent_dup (hp),
|
||
|
- exp = export_allowed (hp, rep->r_path))) {
|
||
|
- /* see if the entry already exists, otherwise this was an instantiated
|
||
|
- * wild card, and we must add it
|
||
|
- */
|
||
|
- nfs_export *exp2 = export_lookup(rep->r_client,
|
||
|
- exp->m_export.e_path, 0);
|
||
|
- if (!exp2) {
|
||
|
- struct exportent ee;
|
||
|
- dupexportent(&ee, &exp->m_export);
|
||
|
- ee.e_hostname = rep->r_client;
|
||
|
- exp2 = export_create(&ee, 0);
|
||
|
- exp2->m_changed = exp->m_changed;
|
||
|
- }
|
||
|
- free (hp);
|
||
|
- exp2->m_mayexport = 1;
|
||
|
- } else if (hp) /* export_allowed failed */
|
||
|
- free(hp);
|
||
|
+ if (htype == MCL_FQDN || htype == MCL_SUBNETWORK)
|
||
|
+ rmtab_read_wildcard(rep);
|
||
|
}
|
||
|
+
|
||
|
if (errno == EINVAL) {
|
||
|
/* Something goes wrong. We need to fix the rmtab
|
||
|
file. */
|
||
|
diff -up nfs-utils-1.2.2/support/include/exportfs.h.orig nfs-utils-1.2.2/support/include/exportfs.h
|
||
|
--- nfs-utils-1.2.2/support/include/exportfs.h.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/support/include/exportfs.h 2010-09-16 16:29:35.229229714 -0400
|
||
|
@@ -10,6 +10,8 @@
|
||
|
#define EXPORTFS_H
|
||
|
|
||
|
#include <netdb.h>
|
||
|
+
|
||
|
+#include "sockaddr.h"
|
||
|
#include "nfslib.h"
|
||
|
|
||
|
enum {
|
||
|
@@ -35,11 +37,56 @@ typedef struct mclient {
|
||
|
char * m_hostname;
|
||
|
int m_type;
|
||
|
int m_naddr;
|
||
|
- struct in_addr m_addrlist[NFSCLNT_ADDRMAX];
|
||
|
+ union nfs_sockaddr m_addrlist[NFSCLNT_ADDRMAX];
|
||
|
int m_exported; /* exported to nfsd */
|
||
|
int m_count;
|
||
|
} nfs_client;
|
||
|
|
||
|
+static inline const struct sockaddr *
|
||
|
+get_addrlist(const nfs_client *clp, const int i)
|
||
|
+{
|
||
|
+ return &clp->m_addrlist[i].sa;
|
||
|
+}
|
||
|
+
|
||
|
+static inline const struct sockaddr_in *
|
||
|
+get_addrlist_in(const nfs_client *clp, const int i)
|
||
|
+{
|
||
|
+ return &clp->m_addrlist[i].s4;
|
||
|
+}
|
||
|
+
|
||
|
+static inline const struct sockaddr_in6 *
|
||
|
+get_addrlist_in6(const nfs_client *clp, const int i)
|
||
|
+{
|
||
|
+ return &clp->m_addrlist[i].s6;
|
||
|
+}
|
||
|
+
|
||
|
+static inline void
|
||
|
+set_addrlist_in(nfs_client *clp, const int i, const struct sockaddr_in *sin)
|
||
|
+{
|
||
|
+ memcpy(&clp->m_addrlist[i].s4, sin, sizeof(*sin));
|
||
|
+}
|
||
|
+
|
||
|
+static inline void
|
||
|
+set_addrlist_in6(nfs_client *clp, const int i, const struct sockaddr_in6 *sin6)
|
||
|
+{
|
||
|
+ memcpy(&clp->m_addrlist[i].s6, sin6, sizeof(*sin6));
|
||
|
+}
|
||
|
+
|
||
|
+static inline void
|
||
|
+set_addrlist(nfs_client *clp, const int i, const struct sockaddr *sap)
|
||
|
+{
|
||
|
+ switch (sap->sa_family) {
|
||
|
+ case AF_INET:
|
||
|
+ memcpy(&clp->m_addrlist[i].s4, sap, sizeof(struct sockaddr_in));
|
||
|
+ break;
|
||
|
+#ifdef IPV6_SUPPORTED
|
||
|
+ case AF_INET6:
|
||
|
+ memcpy(&clp->m_addrlist[i].s6, sap, sizeof(struct sockaddr_in6));
|
||
|
+ break;
|
||
|
+#endif
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
typedef struct mexport {
|
||
|
struct mexport * m_next;
|
||
|
struct mclient * m_client;
|
||
|
@@ -69,26 +116,26 @@ extern exp_hash_table exportlist[MCL_MAX
|
||
|
extern nfs_client * clientlist[MCL_MAXTYPES];
|
||
|
|
||
|
nfs_client * client_lookup(char *hname, int canonical);
|
||
|
-nfs_client * client_find(struct hostent *);
|
||
|
-void client_add(nfs_client *);
|
||
|
-nfs_client * client_dup(nfs_client *, struct hostent *);
|
||
|
+nfs_client * client_dup(const nfs_client *clp,
|
||
|
+ const struct addrinfo *ai);
|
||
|
int client_gettype(char *hname);
|
||
|
-int client_check(nfs_client *, struct hostent *);
|
||
|
-int client_match(nfs_client *, char *hname);
|
||
|
+int client_check(const nfs_client *clp,
|
||
|
+ const struct addrinfo *ai);
|
||
|
void client_release(nfs_client *);
|
||
|
void client_freeall(void);
|
||
|
-char * client_compose(struct hostent *he);
|
||
|
-struct hostent * client_resolve(struct in_addr addr);
|
||
|
-int client_member(char *client, char *name);
|
||
|
+char * client_compose(const struct addrinfo *ai);
|
||
|
+struct addrinfo * client_resolve(const struct sockaddr *sap);
|
||
|
+int client_member(const char *client,
|
||
|
+ const char *name);
|
||
|
|
||
|
-int export_read(char *fname);
|
||
|
-void export_add(nfs_export *);
|
||
|
+void export_read(char *fname);
|
||
|
void export_reset(nfs_export *);
|
||
|
nfs_export * export_lookup(char *hname, char *path, int caconical);
|
||
|
-nfs_export * export_find(struct hostent *, char *path);
|
||
|
-nfs_export * export_allowed(struct hostent *, char *path);
|
||
|
+nfs_export * export_find(const struct addrinfo *ai,
|
||
|
+ const char *path);
|
||
|
+nfs_export * export_allowed(const struct addrinfo *ai,
|
||
|
+ const char *path);
|
||
|
nfs_export * export_create(struct exportent *, int canonical);
|
||
|
-nfs_export * export_dup(nfs_export *, struct hostent *);
|
||
|
void export_freeall(void);
|
||
|
int export_export(nfs_export *);
|
||
|
int export_unexport(nfs_export *);
|
||
|
@@ -101,6 +148,19 @@ void xtab_append(nfs_export *);
|
||
|
|
||
|
int secinfo_addflavor(struct flav_info *, struct exportent *);
|
||
|
|
||
|
+char * host_ntop(const struct sockaddr *sap,
|
||
|
+ char *buf, const size_t buflen);
|
||
|
+__attribute_malloc__
|
||
|
+struct addrinfo * host_pton(const char *paddr);
|
||
|
+__attribute_malloc__
|
||
|
+struct addrinfo * host_addrinfo(const char *hostname);
|
||
|
+__attribute_malloc__
|
||
|
+char * host_canonname(const struct sockaddr *sap);
|
||
|
+__attribute_malloc__
|
||
|
+struct addrinfo * host_reliable_addrinfo(const struct sockaddr *sap);
|
||
|
+__attribute_malloc__
|
||
|
+struct addrinfo * host_numeric_addrinfo(const struct sockaddr *sap);
|
||
|
+
|
||
|
int rmtab_read(void);
|
||
|
|
||
|
struct nfskey * key_lookup(char *hname);
|
||
|
diff -up nfs-utils-1.2.2/support/include/misc.h.orig nfs-utils-1.2.2/support/include/misc.h
|
||
|
--- nfs-utils-1.2.2/support/include/misc.h.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/support/include/misc.h 2010-09-16 16:29:35.229229714 -0400
|
||
|
@@ -15,13 +15,6 @@
|
||
|
int randomkey(unsigned char *keyout, int len);
|
||
|
int weakrandomkey(unsigned char *keyout, int len);
|
||
|
|
||
|
-int matchhostname(const char *h1, const char *h2);
|
||
|
-
|
||
|
-struct hostent;
|
||
|
-struct hostent *hostent_dup(struct hostent *hp);
|
||
|
-struct hostent *get_hostent (const char *addr, int len, int type);
|
||
|
-struct hostent *get_reliable_hostbyaddr(const char *addr, int len, int type);
|
||
|
-
|
||
|
extern int is_mountpoint(char *path);
|
||
|
|
||
|
#endif /* MISC_H */
|
||
|
diff -up nfs-utils-1.2.2/support/include/nfslib.h.orig nfs-utils-1.2.2/support/include/nfslib.h
|
||
|
--- nfs-utils-1.2.2/support/include/nfslib.h.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/support/include/nfslib.h 2010-09-16 16:29:35.230230090 -0400
|
||
|
@@ -83,7 +83,7 @@ struct exportent {
|
||
|
int e_nsquids;
|
||
|
int * e_sqgids;
|
||
|
int e_nsqgids;
|
||
|
- int e_fsid;
|
||
|
+ unsigned int e_fsid;
|
||
|
char * e_mountpoint;
|
||
|
int e_fslocmethod;
|
||
|
char * e_fslocdata;
|
||
|
@@ -134,9 +134,12 @@ int nfsaddclient(struct nfsctl_client
|
||
|
int nfsdelclient(struct nfsctl_client *clp);
|
||
|
int nfsexport(struct nfsctl_export *exp);
|
||
|
int nfsunexport(struct nfsctl_export *exp);
|
||
|
-struct nfs_fh_len * getfh_old(struct sockaddr *addr, dev_t dev, ino_t ino);
|
||
|
-struct nfs_fh_len * getfh(struct sockaddr *addr, const char *);
|
||
|
-struct nfs_fh_len * getfh_size(struct sockaddr *addr, const char *, int size);
|
||
|
+
|
||
|
+struct nfs_fh_len * getfh_old(const struct sockaddr_in *sin,
|
||
|
+ const dev_t dev, const ino_t ino);
|
||
|
+struct nfs_fh_len * getfh(const struct sockaddr_in *sin, const char *path);
|
||
|
+struct nfs_fh_len * getfh_size(const struct sockaddr_in *sin,
|
||
|
+ const char *path, int const size);
|
||
|
|
||
|
void qword_print(FILE *f, char *str);
|
||
|
void qword_printhex(FILE *f, char *str, int slen);
|
||
|
@@ -152,10 +155,15 @@ void qword_addhex(char **bpp, int *lp, c
|
||
|
void qword_addint(char **bpp, int *lp, int n);
|
||
|
void qword_adduint(char **bpp, int *lp, unsigned int n);
|
||
|
void qword_addeol(char **bpp, int *lp);
|
||
|
+int qword_get_uint(char **bpp, unsigned int *anint);
|
||
|
+void qword_printuint(FILE *f, unsigned int num);
|
||
|
|
||
|
void closeall(int min);
|
||
|
|
||
|
int svctcp_socket (u_long __number, int __reuse);
|
||
|
-int svcudp_socket (u_long __number, int __reuse);
|
||
|
+int svcudp_socket (u_long __number);
|
||
|
+
|
||
|
+
|
||
|
+#define UNUSED(x) UNUSED_ ## x __attribute__((unused))
|
||
|
|
||
|
#endif /* NFSLIB_H */
|
||
|
diff -up nfs-utils-1.2.2/support/include/nfsrpc.h.orig nfs-utils-1.2.2/support/include/nfsrpc.h
|
||
|
--- nfs-utils-1.2.2/support/include/nfsrpc.h.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/support/include/nfsrpc.h 2010-09-16 16:29:35.230230090 -0400
|
||
|
@@ -27,6 +27,12 @@
|
||
|
#include <rpc/clnt.h>
|
||
|
|
||
|
/*
|
||
|
+ * IANA does not define an IP protocol number for RDMA transports.
|
||
|
+ * Choose an arbitrary value we can use locally.
|
||
|
+ */
|
||
|
+#define NFSPROTO_RDMA (3939)
|
||
|
+
|
||
|
+/*
|
||
|
* Conventional RPC program numbers
|
||
|
*/
|
||
|
#ifndef RPCBPROG
|
||
|
@@ -160,4 +166,7 @@ extern int nfs_rpc_ping(const struct so
|
||
|
const unsigned short protocol,
|
||
|
const struct timeval *timeout);
|
||
|
|
||
|
+/* create AUTH_SYS handle with no supplemental groups */
|
||
|
+extern AUTH * nfs_authsys_create(void);
|
||
|
+
|
||
|
#endif /* !__NFS_UTILS_NFSRPC_H */
|
||
|
diff -up nfs-utils-1.2.2/support/include/rpcmisc.h.orig nfs-utils-1.2.2/support/include/rpcmisc.h
|
||
|
--- nfs-utils-1.2.2/support/include/rpcmisc.h.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/support/include/rpcmisc.h 2010-09-16 16:29:35.231240528 -0400
|
||
|
@@ -60,12 +60,12 @@ extern int _rpcsvcdirty;
|
||
|
|
||
|
static inline struct sockaddr_in *nfs_getrpccaller_in(SVCXPRT *xprt)
|
||
|
{
|
||
|
- return (struct sockaddr_in *)svc_getcaller(xprt);
|
||
|
+ return (struct sockaddr_in *)(char *)svc_getcaller(xprt);
|
||
|
}
|
||
|
|
||
|
static inline struct sockaddr *nfs_getrpccaller(SVCXPRT *xprt)
|
||
|
{
|
||
|
- return (struct sockaddr *)svc_getcaller(xprt);
|
||
|
+ return (struct sockaddr *)(char *)svc_getcaller(xprt);
|
||
|
}
|
||
|
|
||
|
#endif /* RPCMISC_H */
|
||
|
diff -up nfs-utils-1.2.2/support/nfs/cacheio.c.orig nfs-utils-1.2.2/support/nfs/cacheio.c
|
||
|
--- nfs-utils-1.2.2/support/nfs/cacheio.c.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/support/nfs/cacheio.c 2010-09-16 16:29:35.232229968 -0400
|
||
|
@@ -148,6 +148,11 @@ void qword_printint(FILE *f, int num)
|
||
|
fprintf(f, "%d ", num);
|
||
|
}
|
||
|
|
||
|
+void qword_printuint(FILE *f, unsigned int num)
|
||
|
+{
|
||
|
+ fprintf(f, "%u ", num);
|
||
|
+}
|
||
|
+
|
||
|
int qword_eol(FILE *f)
|
||
|
{
|
||
|
int err;
|
||
|
@@ -236,6 +241,20 @@ int qword_get_int(char **bpp, int *anint
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
+int qword_get_uint(char **bpp, unsigned int *anint)
|
||
|
+{
|
||
|
+ char buf[50];
|
||
|
+ char *ep;
|
||
|
+ unsigned int rv;
|
||
|
+ int len = qword_get(bpp, buf, 50);
|
||
|
+ if (len < 0) return -1;
|
||
|
+ if (len ==0) return -1;
|
||
|
+ rv = strtoul(buf, &ep, 0);
|
||
|
+ if (*ep) return -1;
|
||
|
+ *anint = rv;
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
#define READLINE_BUFFER_INCREMENT 2048
|
||
|
|
||
|
int readline(int fd, char **buf, int *lenp)
|
||
|
@@ -330,7 +349,7 @@ cache_flush(int force)
|
||
|
sprintf(path, "/proc/net/rpc/%s/flush", cachelist[c]);
|
||
|
fd = open(path, O_RDWR);
|
||
|
if (fd >= 0) {
|
||
|
- if (write(fd, stime, strlen(stime)) != strlen(stime)) {
|
||
|
+ if (write(fd, stime, strlen(stime)) != (ssize_t)strlen(stime)) {
|
||
|
xlog_warn("Writing to '%s' failed: errno %d (%s)",
|
||
|
path, errno, strerror(errno));
|
||
|
}
|
||
|
diff -up nfs-utils-1.2.2/support/nfs/conffile.c.orig nfs-utils-1.2.2/support/nfs/conffile.c
|
||
|
--- nfs-utils-1.2.2/support/nfs/conffile.c.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/support/nfs/conffile.c 2010-09-16 16:29:35.232229968 -0400
|
||
|
@@ -49,7 +49,7 @@
|
||
|
#include "conffile.h"
|
||
|
#include "xlog.h"
|
||
|
|
||
|
-static void conf_load_defaults (int);
|
||
|
+static void conf_load_defaults(void);
|
||
|
static int conf_set(int , char *, char *, char *,
|
||
|
char *, int , int );
|
||
|
|
||
|
@@ -212,7 +212,7 @@ conf_parse_line(int trans, char *line, s
|
||
|
{
|
||
|
char *val, *ptr;
|
||
|
size_t i;
|
||
|
- int j;
|
||
|
+ size_t j;
|
||
|
static char *section = 0;
|
||
|
static char *arg = 0;
|
||
|
static int ln = 0;
|
||
|
@@ -353,7 +353,7 @@ conf_parse(int trans, char *buf, size_t
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
-conf_load_defaults(int tr)
|
||
|
+conf_load_defaults(void)
|
||
|
{
|
||
|
/* No defaults */
|
||
|
return;
|
||
|
@@ -412,7 +412,7 @@ conf_reinit(void)
|
||
|
trans = conf_begin();
|
||
|
|
||
|
/* Load default configuration values. */
|
||
|
- conf_load_defaults(trans);
|
||
|
+ conf_load_defaults();
|
||
|
|
||
|
/* Free potential existing configuration. */
|
||
|
if (conf_addr) {
|
||
|
diff -up nfs-utils-1.2.2/support/nfs/getfh.c.orig nfs-utils-1.2.2/support/nfs/getfh.c
|
||
|
--- nfs-utils-1.2.2/support/nfs/getfh.c.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/support/nfs/getfh.c 2010-09-16 16:29:35.233230434 -0400
|
||
|
@@ -19,60 +19,112 @@
|
||
|
#include <errno.h>
|
||
|
#include "nfslib.h"
|
||
|
|
||
|
+/**
|
||
|
+ * getfh_old - ask the kernel for an NFSv2 file handle via nfsctl()
|
||
|
+ * @sin: pointer to IPv4 address of a client
|
||
|
+ * @dev: device number of device where requested object resides
|
||
|
+ * @ino: inode number of requested object
|
||
|
+ *
|
||
|
+ * Returns a pointer to an NFSv2 file handle, or NULL if some error
|
||
|
+ * occurred. errno is set to reflect the specifics of the error.
|
||
|
+ */
|
||
|
struct nfs_fh_len *
|
||
|
-getfh_old (struct sockaddr *addr, dev_t dev, ino_t ino)
|
||
|
+getfh_old(const struct sockaddr_in *sin, const dev_t dev, const ino_t ino)
|
||
|
{
|
||
|
union nfsctl_res res;
|
||
|
struct nfsctl_arg arg;
|
||
|
static struct nfs_fh_len rfh;
|
||
|
|
||
|
+ if (sin->sin_family != AF_INET) {
|
||
|
+ errno = EAFNOSUPPORT;
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ memset(&arg, 0, sizeof(arg));
|
||
|
+ memset(&res, 0, sizeof(res));
|
||
|
+
|
||
|
arg.ca_version = NFSCTL_VERSION;
|
||
|
arg.ca_getfh.gf_version = 2; /* obsolete */
|
||
|
arg.ca_getfh.gf_dev = dev;
|
||
|
arg.ca_getfh.gf_ino = ino;
|
||
|
- memcpy(&arg.ca_getfh.gf_addr, addr, sizeof(struct sockaddr_in));
|
||
|
+ memcpy(&arg.ca_getfh.gf_addr, sin, sizeof(*sin));
|
||
|
|
||
|
if (nfsctl(NFSCTL_GETFH, &arg, &res) < 0)
|
||
|
return NULL;
|
||
|
|
||
|
+ memset(&rfh, 0, sizeof(rfh));
|
||
|
rfh.fh_size = 32;
|
||
|
memcpy(rfh.fh_handle, &res.cr_getfh, 32);
|
||
|
return &rfh;
|
||
|
}
|
||
|
|
||
|
+/**
|
||
|
+ * getfh - ask the kernel for an NFSv2 file handle via nfsctl()
|
||
|
+ * @sin: pointer to IPv4 address of a client
|
||
|
+ * @path: pointer to a '\0'-terminated ASCII string containing an pathname
|
||
|
+ *
|
||
|
+ * Returns a pointer to an NFSv2 file handle, or NULL if some error
|
||
|
+ * occurred. errno is set to reflect the specifics of the error.
|
||
|
+ */
|
||
|
struct nfs_fh_len *
|
||
|
-getfh(struct sockaddr *addr, const char *path)
|
||
|
+getfh(const struct sockaddr_in *sin, const char *path)
|
||
|
{
|
||
|
static union nfsctl_res res;
|
||
|
struct nfsctl_arg arg;
|
||
|
static struct nfs_fh_len rfh;
|
||
|
|
||
|
+ if (sin->sin_family != AF_INET) {
|
||
|
+ errno = EAFNOSUPPORT;
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ memset(&arg, 0, sizeof(arg));
|
||
|
+ memset(&res, 0, sizeof(res));
|
||
|
+
|
||
|
arg.ca_version = NFSCTL_VERSION;
|
||
|
arg.ca_getfd.gd_version = 2; /* obsolete */
|
||
|
strncpy(arg.ca_getfd.gd_path, path,
|
||
|
sizeof(arg.ca_getfd.gd_path) - 1);
|
||
|
arg.ca_getfd.gd_path[sizeof (arg.ca_getfd.gd_path) - 1] = '\0';
|
||
|
- memcpy(&arg.ca_getfd.gd_addr, addr, sizeof(struct sockaddr_in));
|
||
|
+ memcpy(&arg.ca_getfd.gd_addr, sin, sizeof(*sin));
|
||
|
|
||
|
if (nfsctl(NFSCTL_GETFD, &arg, &res) < 0)
|
||
|
return NULL;
|
||
|
|
||
|
+ memset(&rfh, 0, sizeof(rfh));
|
||
|
rfh.fh_size = 32;
|
||
|
memcpy(rfh.fh_handle, &res.cr_getfh, 32);
|
||
|
return &rfh;
|
||
|
}
|
||
|
|
||
|
+/**
|
||
|
+ * getfh_size - ask the kernel for a file handle via nfsctl()
|
||
|
+ * @sin: pointer to IPv4 address of a client
|
||
|
+ * @path: pointer to a '\0'-terminated ASCII string containing an pathname
|
||
|
+ * @size: maximum size, in bytes, of the returned file handle
|
||
|
+ *
|
||
|
+ * Returns a pointer to an NFSv3 file handle, or NULL if some error
|
||
|
+ * occurred. errno is set to reflect the specifics of the error.
|
||
|
+ */
|
||
|
struct nfs_fh_len *
|
||
|
-getfh_size(struct sockaddr *addr, const char *path, int size)
|
||
|
+getfh_size(const struct sockaddr_in *sin, const char *path, const int size)
|
||
|
{
|
||
|
static union nfsctl_res res;
|
||
|
struct nfsctl_arg arg;
|
||
|
|
||
|
+ if (sin->sin_family != AF_INET) {
|
||
|
+ errno = EAFNOSUPPORT;
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ memset(&arg, 0, sizeof(arg));
|
||
|
+ memset(&res, 0, sizeof(res));
|
||
|
+
|
||
|
arg.ca_version = NFSCTL_VERSION;
|
||
|
strncpy(arg.ca_getfs.gd_path, path,
|
||
|
sizeof(arg.ca_getfs.gd_path) - 1);
|
||
|
arg.ca_getfs.gd_path[sizeof (arg.ca_getfs.gd_path) - 1] = '\0';
|
||
|
- memcpy(&arg.ca_getfs.gd_addr, addr, sizeof(struct sockaddr_in));
|
||
|
+ memcpy(&arg.ca_getfs.gd_addr, sin, sizeof(*sin));
|
||
|
arg.ca_getfs.gd_maxlen = size;
|
||
|
|
||
|
if (nfsctl(NFSCTL_GETFS, &arg, &res) < 0)
|
||
|
diff -up nfs-utils-1.2.2/support/nfs/getport.c.orig nfs-utils-1.2.2/support/nfs/getport.c
|
||
|
--- nfs-utils-1.2.2/support/nfs/getport.c.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/support/nfs/getport.c 2010-09-16 16:29:35.234229813 -0400
|
||
|
@@ -216,6 +216,21 @@ nfs_get_proto(const char *netid, sa_fami
|
||
|
struct netconfig *nconf;
|
||
|
struct protoent *proto;
|
||
|
|
||
|
+ /*
|
||
|
+ * IANA does not define a protocol number for rdma netids,
|
||
|
+ * since "rdma" is not an IP protocol.
|
||
|
+ */
|
||
|
+ if (strcmp(netid, "rdma") == 0) {
|
||
|
+ *family = AF_INET;
|
||
|
+ *protocol = NFSPROTO_RDMA;
|
||
|
+ return 1;
|
||
|
+ }
|
||
|
+ if (strcmp(netid, "rdma6") == 0) {
|
||
|
+ *family = AF_INET6;
|
||
|
+ *protocol = NFSPROTO_RDMA;
|
||
|
+ return 1;
|
||
|
+ }
|
||
|
+
|
||
|
nconf = getnetconfigent(netid);
|
||
|
if (nconf == NULL)
|
||
|
return 0;
|
||
|
@@ -242,6 +257,16 @@ nfs_get_proto(const char *netid, sa_fami
|
||
|
{
|
||
|
struct protoent *proto;
|
||
|
|
||
|
+ /*
|
||
|
+ * IANA does not define a protocol number for rdma netids,
|
||
|
+ * since "rdma" is not an IP protocol.
|
||
|
+ */
|
||
|
+ if (strcmp(netid, "rdma") == 0) {
|
||
|
+ *family = AF_INET;
|
||
|
+ *protocol = NFSPROTO_RDMA;
|
||
|
+ return 1;
|
||
|
+ }
|
||
|
+
|
||
|
proto = getprotobyname(netid);
|
||
|
if (proto == NULL)
|
||
|
return 0;
|
||
|
diff -up nfs-utils-1.2.2/support/nfs/nfs_mntent.c.orig nfs-utils-1.2.2/support/nfs/nfs_mntent.c
|
||
|
--- nfs-utils-1.2.2/support/nfs/nfs_mntent.c.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/support/nfs/nfs_mntent.c 2010-09-16 16:29:35.234229813 -0400
|
||
|
@@ -28,7 +28,7 @@ static char *
|
||
|
mangle(const char *arg) {
|
||
|
const unsigned char *s = (const unsigned char *)arg;
|
||
|
char *ss, *sp;
|
||
|
- int n;
|
||
|
+ unsigned int n;
|
||
|
|
||
|
n = strlen(arg);
|
||
|
ss = sp = xmalloc(4*n+1);
|
||
|
diff -up nfs-utils-1.2.2/support/nfs/rmtab.c.orig nfs-utils-1.2.2/support/nfs/rmtab.c
|
||
|
--- nfs-utils-1.2.2/support/nfs/rmtab.c.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/support/nfs/rmtab.c 2010-09-16 16:29:35.235219822 -0400
|
||
|
@@ -19,6 +19,18 @@
|
||
|
#include <signal.h>
|
||
|
#include "nfslib.h"
|
||
|
|
||
|
+/*
|
||
|
+ * Colons in incoming IPv6 presentation addresses have to
|
||
|
+ * replaced with another character, since rmtab already
|
||
|
+ * uses colons to delineate fields.
|
||
|
+ *
|
||
|
+ * Use a printable character, but one that would never be
|
||
|
+ * found in a presentation address or domain name
|
||
|
+ */
|
||
|
+#define IPV6_COLON ';'
|
||
|
+
|
||
|
+#define LINELEN (2048)
|
||
|
+
|
||
|
static FILE *rmfp = NULL;
|
||
|
|
||
|
int
|
||
|
@@ -56,7 +68,8 @@ struct rmtabent *
|
||
|
fgetrmtabent(FILE *fp, int log, long *pos)
|
||
|
{
|
||
|
static struct rmtabent re;
|
||
|
- char buf[2048], *count, *host, *path;
|
||
|
+ char *count, *host, *path, *c;
|
||
|
+ static char buf[LINELEN];
|
||
|
|
||
|
errno = 0;
|
||
|
if (!fp)
|
||
|
@@ -84,10 +97,16 @@ fgetrmtabent(FILE *fp, int log, long *po
|
||
|
else
|
||
|
re.r_count = 1;
|
||
|
} while (0);
|
||
|
+
|
||
|
strncpy(re.r_client, host, sizeof (re.r_client) - 1);
|
||
|
re.r_client[sizeof (re.r_client) - 1] = '\0';
|
||
|
+ for (c = re.r_client; *c != '\0'; c++)
|
||
|
+ if (*c == IPV6_COLON)
|
||
|
+ *c = ':';
|
||
|
+
|
||
|
strncpy(re.r_path, path, sizeof (re.r_path) - 1);
|
||
|
re.r_path[sizeof (re.r_path) - 1] = '\0';
|
||
|
+
|
||
|
return &re;
|
||
|
}
|
||
|
|
||
|
@@ -100,10 +119,27 @@ putrmtabent(struct rmtabent *rep, long *
|
||
|
void
|
||
|
fputrmtabent(FILE *fp, struct rmtabent *rep, long *pos)
|
||
|
{
|
||
|
+ static char buf[LINELEN];
|
||
|
+ char *c;
|
||
|
+
|
||
|
if (!fp || (pos && fseek (fp, *pos, SEEK_SET) != 0))
|
||
|
return;
|
||
|
- fprintf(fp, "%s:%s:0x%.8x\n", rep->r_client, rep->r_path,
|
||
|
- rep->r_count);
|
||
|
+
|
||
|
+ /*
|
||
|
+ * To avoid confusing the token parser in fgetrmtabent(),
|
||
|
+ * convert colons in incoming IPv6 presentation addresses
|
||
|
+ * to semicolons.
|
||
|
+ */
|
||
|
+ if (strlen(rep->r_client) > sizeof(buf)) {
|
||
|
+ xlog(L_ERROR, "client name too large");
|
||
|
+ return;
|
||
|
+ }
|
||
|
+ strncpy(buf, rep->r_client, sizeof(buf));
|
||
|
+ for (c = buf; *c != '\0'; c++)
|
||
|
+ if (*c == ':')
|
||
|
+ *c = IPV6_COLON;
|
||
|
+
|
||
|
+ (void)fprintf(fp, "%s:%s:0x%.8x\n", buf, rep->r_path, rep->r_count);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
diff -up nfs-utils-1.2.2/support/nfs/rpcdispatch.c.orig nfs-utils-1.2.2/support/nfs/rpcdispatch.c
|
||
|
--- nfs-utils-1.2.2/support/nfs/rpcdispatch.c.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/support/nfs/rpcdispatch.c 2010-09-16 16:29:35.236229903 -0400
|
||
|
@@ -27,12 +27,12 @@ rpc_dispatch(struct svc_req *rqstp, SVCX
|
||
|
{
|
||
|
struct rpc_dentry *dent;
|
||
|
|
||
|
- if (rqstp->rq_vers > nvers) {
|
||
|
+ if (((int)rqstp->rq_vers) > nvers) {
|
||
|
svcerr_progvers(transp, 1, nvers);
|
||
|
return;
|
||
|
}
|
||
|
dtable += (rqstp->rq_vers - 1);
|
||
|
- if (rqstp->rq_proc > dtable->nproc) {
|
||
|
+ if (((int)rqstp->rq_proc) > dtable->nproc) {
|
||
|
svcerr_noproc(transp);
|
||
|
return;
|
||
|
}
|
||
|
diff -up nfs-utils-1.2.2/support/nfs/rpcmisc.c.orig nfs-utils-1.2.2/support/nfs/rpcmisc.c
|
||
|
--- nfs-utils-1.2.2/support/nfs/rpcmisc.c.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/support/nfs/rpcmisc.c 2010-09-16 16:29:35.237240603 -0400
|
||
|
@@ -154,7 +154,7 @@ rpc_init(char *name, int prog, int vers,
|
||
|
sock = makesock(defport, IPPROTO_UDP);
|
||
|
}
|
||
|
if (sock == RPC_ANYSOCK)
|
||
|
- sock = svcudp_socket (prog, 1);
|
||
|
+ sock = svcudp_socket (prog);
|
||
|
transp = svcudp_create(sock);
|
||
|
if (transp == NULL) {
|
||
|
xlog(L_FATAL, "cannot create udp service.");
|
||
|
diff -up nfs-utils-1.2.2/support/nfs/rpc_socket.c.orig nfs-utils-1.2.2/support/nfs/rpc_socket.c
|
||
|
--- nfs-utils-1.2.2/support/nfs/rpc_socket.c.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/support/nfs/rpc_socket.c 2010-09-16 16:29:35.236229903 -0400
|
||
|
@@ -557,3 +557,24 @@ rpcprog_t nfs_getrpcbyname(const rpcprog
|
||
|
|
||
|
return program;
|
||
|
}
|
||
|
+
|
||
|
+/*
|
||
|
+ * AUTH_SYS doesn't allow more than 16 gids in the supplemental group list.
|
||
|
+ * If there are more than that, trying to determine which ones to include
|
||
|
+ * in the list is problematic. This function creates an auth handle that
|
||
|
+ * only has the primary gid in the supplemental gids list. It's intended to
|
||
|
+ * be used for protocols where credentials really don't matter much (the MNT
|
||
|
+ * protocol, for instance).
|
||
|
+ */
|
||
|
+AUTH *
|
||
|
+nfs_authsys_create(void)
|
||
|
+{
|
||
|
+ char machname[MAXHOSTNAMELEN + 1];
|
||
|
+ uid_t uid = geteuid();
|
||
|
+ gid_t gid = getegid();
|
||
|
+
|
||
|
+ if (gethostname(machname, sizeof(machname)) == -1)
|
||
|
+ return NULL;
|
||
|
+
|
||
|
+ return authunix_create(machname, uid, gid, 1, &gid);
|
||
|
+}
|
||
|
diff -up nfs-utils-1.2.2/support/nfs/svc_socket.c.orig nfs-utils-1.2.2/support/nfs/svc_socket.c
|
||
|
--- nfs-utils-1.2.2/support/nfs/svc_socket.c.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/support/nfs/svc_socket.c 2010-09-16 16:29:35.237240603 -0400
|
||
|
@@ -157,9 +157,9 @@ svctcp_socket (u_long number, int reuse)
|
||
|
* Create and bind a UDP socket based on program number
|
||
|
*/
|
||
|
int
|
||
|
-svcudp_socket (u_long number, int reuse)
|
||
|
+svcudp_socket (u_long number)
|
||
|
{
|
||
|
- return svc_socket (number, SOCK_DGRAM, IPPROTO_UDP, 0);
|
||
|
+ return svc_socket (number, SOCK_DGRAM, IPPROTO_UDP, FALSE);
|
||
|
}
|
||
|
|
||
|
#ifdef TEST
|
||
|
@@ -174,7 +174,7 @@ check (u_long number, u_short port, int
|
||
|
if (protocol == IPPROTO_TCP)
|
||
|
socket = svctcp_socket (number, reuse);
|
||
|
else
|
||
|
- socket = svcudp_socket (number, reuse);
|
||
|
+ socket = svcudp_socket (number);
|
||
|
|
||
|
if (socket < 0)
|
||
|
return 1;
|
||
|
diff -up nfs-utils-1.2.2/support/nsm/file.c.orig nfs-utils-1.2.2/support/nsm/file.c
|
||
|
--- nfs-utils-1.2.2/support/nsm/file.c.orig 2010-09-16 15:40:15.598012398 -0400
|
||
|
+++ nfs-utils-1.2.2/support/nsm/file.c 2010-09-16 16:29:35.238240456 -0400
|
||
|
@@ -67,7 +67,9 @@
|
||
|
#endif
|
||
|
|
||
|
#include <sys/types.h>
|
||
|
+#ifdef HAVE_SYS_CAPABILITY_H
|
||
|
#include <sys/capability.h>
|
||
|
+#endif
|
||
|
#include <sys/prctl.h>
|
||
|
#include <sys/stat.h>
|
||
|
|
||
|
@@ -348,6 +350,7 @@ nsm_is_default_parentdir(void)
|
||
|
static _Bool
|
||
|
nsm_clear_capabilities(void)
|
||
|
{
|
||
|
+#ifdef HAVE_SYS_CAPABILITY_H
|
||
|
cap_t caps;
|
||
|
|
||
|
caps = cap_from_text("cap_net_bind_service=ep");
|
||
|
@@ -363,6 +366,7 @@ nsm_clear_capabilities(void)
|
||
|
}
|
||
|
|
||
|
(void)cap_free(caps);
|
||
|
+#endif
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
diff -up nfs-utils-1.2.2/tools/Makefile.am.orig nfs-utils-1.2.2/tools/Makefile.am
|
||
|
--- nfs-utils-1.2.2/tools/Makefile.am.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/tools/Makefile.am 2010-09-16 16:29:35.239219806 -0400
|
||
|
@@ -6,6 +6,6 @@ if CONFIG_RPCGEN
|
||
|
OPTDIRS += rpcgen
|
||
|
endif
|
||
|
|
||
|
-SUBDIRS = locktest rpcdebug nlmtest $(OPTDIRS)
|
||
|
+SUBDIRS = locktest rpcdebug nlmtest mountstats nfs-iostat $(OPTDIRS)
|
||
|
|
||
|
MAINTAINERCLEANFILES = Makefile.in
|
||
|
diff -up nfs-utils-1.2.2/tools/mountstats/Makefile.am.orig nfs-utils-1.2.2/tools/mountstats/Makefile.am
|
||
|
--- nfs-utils-1.2.2/tools/mountstats/Makefile.am.orig 2010-09-16 16:29:35.239219806 -0400
|
||
|
+++ nfs-utils-1.2.2/tools/mountstats/Makefile.am 2010-09-16 16:29:35.239219806 -0400
|
||
|
@@ -0,0 +1,13 @@
|
||
|
+## Process this file with automake to produce Makefile.in
|
||
|
+PYTHON_FILES = mountstats.py
|
||
|
+
|
||
|
+man8_MANS = mountstats.man
|
||
|
+
|
||
|
+EXTRA_DIST = $(man8_MANS) $(PYTHON_FILES)
|
||
|
+
|
||
|
+all-local: $(PYTHON_FILES)
|
||
|
+
|
||
|
+install-data-hook:
|
||
|
+ $(INSTALL) --mode 755 mountstats.py $(DESTDIR)$(sbindir)/mountstats
|
||
|
+
|
||
|
+MAINTAINERCLEANFILES=Makefile.in
|
||
|
diff -up nfs-utils-1.2.2/tools/mountstats/mountstats.man.orig nfs-utils-1.2.2/tools/mountstats/mountstats.man
|
||
|
--- nfs-utils-1.2.2/tools/mountstats/mountstats.man.orig 2010-09-16 16:29:35.240054628 -0400
|
||
|
+++ nfs-utils-1.2.2/tools/mountstats/mountstats.man 2010-09-16 16:29:35.240054628 -0400
|
||
|
@@ -0,0 +1,32 @@
|
||
|
+.\"
|
||
|
+.\" mountstats(8)
|
||
|
+.\"
|
||
|
+.TH mountstats 8 "15 Apr 2010"
|
||
|
+.SH NAME
|
||
|
+mountstats \- Displays NFS client per-mount statistics
|
||
|
+.SH SYNOPSIS
|
||
|
+.BI "mountstats ["<options> "] " <mount_point> " [ " <mount_point> "]"
|
||
|
+.SH DESCRIPTION
|
||
|
+The
|
||
|
+.B mountstats
|
||
|
+command displays NFS client statisitics on each given
|
||
|
+.I <mount_point>
|
||
|
+.SH OPTIONS
|
||
|
+.TP
|
||
|
+.B " \-\-nfs
|
||
|
+display only the NFS statistics
|
||
|
+.TP
|
||
|
+.B " \-\-rpc
|
||
|
+display only the RPC statistics
|
||
|
+.TP
|
||
|
+.B " \-\-version
|
||
|
+display the version of this command
|
||
|
+.SH FILES
|
||
|
+.TP
|
||
|
+.B /proc/self/mountstats
|
||
|
+.SH SEE ALSO
|
||
|
+.BR iostat (8),
|
||
|
+.BR nfsiostat (8),
|
||
|
+.BR nfsstat(8)
|
||
|
+.SH AUTHOR
|
||
|
+Chuck Lever <chuck.lever@oracle.com>
|
||
|
diff -up nfs-utils-1.2.2/tools/nfs-iostat/Makefile.am.orig nfs-utils-1.2.2/tools/nfs-iostat/Makefile.am
|
||
|
--- nfs-utils-1.2.2/tools/nfs-iostat/Makefile.am.orig 2010-09-16 16:29:35.240054628 -0400
|
||
|
+++ nfs-utils-1.2.2/tools/nfs-iostat/Makefile.am 2010-09-16 16:29:35.240054628 -0400
|
||
|
@@ -0,0 +1,13 @@
|
||
|
+## Process this file with automake to produce Makefile.in
|
||
|
+PYTHON_FILES = nfs-iostat.py
|
||
|
+
|
||
|
+man8_MANS = nfsiostat.man
|
||
|
+
|
||
|
+EXTRA_DIST = $(man8_MANS) $(PYTHON_FILES)
|
||
|
+
|
||
|
+all-local: $(PYTHON_FILES)
|
||
|
+
|
||
|
+install-data-hook:
|
||
|
+ $(INSTALL) --mode 755 nfs-iostat.py $(DESTDIR)$(sbindir)/nfsiostat
|
||
|
+
|
||
|
+MAINTAINERCLEANFILES=Makefile.in
|
||
|
diff -up nfs-utils-1.2.2/tools/nfs-iostat/nfsiostat.man.orig nfs-utils-1.2.2/tools/nfs-iostat/nfsiostat.man
|
||
|
--- nfs-utils-1.2.2/tools/nfs-iostat/nfsiostat.man.orig 2010-09-16 16:29:35.241239795 -0400
|
||
|
+++ nfs-utils-1.2.2/tools/nfs-iostat/nfsiostat.man 2010-09-16 16:29:35.241239795 -0400
|
||
|
@@ -0,0 +1,71 @@
|
||
|
+.\"
|
||
|
+.\" nfsiostat(8)
|
||
|
+.\"
|
||
|
+.TH nfsiostat 8 "15 Apr 2010"
|
||
|
+.SH NAME
|
||
|
+nfsiostat \- Emulate iostat for NFS mount points using /proc/self/mountstats
|
||
|
+.SH SYNOPSIS
|
||
|
+.BI "nfsiostat [[" <interval> "] [" <count> "]] [" <options> "]["<mount_point> "]
|
||
|
+.SH DESCRIPTION
|
||
|
+The
|
||
|
+.B nfsiostat
|
||
|
+command displays NFS client per-mount statisitics.
|
||
|
+.TP
|
||
|
+<interval>
|
||
|
+specifies the amount of time in seconds between each report.
|
||
|
+The first report contains statistics for the time since each file
|
||
|
+system was mounted. Each subsequent report contains statistics collected
|
||
|
+during the interval since the previous report.
|
||
|
+.TP
|
||
|
+<count>
|
||
|
+If the
|
||
|
+.I <count>
|
||
|
+parameter is
|
||
|
+specified, the value of
|
||
|
+.I <count>
|
||
|
+determines the number of reports generated at
|
||
|
+. <interval>
|
||
|
+seconds apart. if the interval parameter is
|
||
|
+specified without the
|
||
|
+.I <count>
|
||
|
+parameter, the command generates reports continuously.
|
||
|
+.TP
|
||
|
+<options>
|
||
|
+Define below
|
||
|
+.TP
|
||
|
+<mount_point>
|
||
|
+If one or more
|
||
|
+.I <mount point>
|
||
|
+names are specified, statistics for only these mount points will
|
||
|
+be displayed. Otherwise, all NFS mount points on the client are listed.
|
||
|
+.SH OPTIONS
|
||
|
+.TP
|
||
|
+.B \-a " or " \-\-attr
|
||
|
+displays statistics related to the attribute cache
|
||
|
+.TP
|
||
|
+.B \-d " or " \-\-dir
|
||
|
+displays statistics related to directory operations
|
||
|
+.TP
|
||
|
+.B \-h " or " \-\-help
|
||
|
+shows help message and exit
|
||
|
+.TP
|
||
|
+.B \-l LIST or " \-\-list=LIST
|
||
|
+only print stats for first LIST mount points
|
||
|
+.TP
|
||
|
+.B \-p " or " \-\-page
|
||
|
+displays statistics related to the page cache
|
||
|
+.TP
|
||
|
+.B \-s " or " \-\-sort
|
||
|
+Sort NFS mount points by ops/second
|
||
|
+.TP
|
||
|
+.B \-\-version
|
||
|
+show program's version number and exit
|
||
|
+.SH FILES
|
||
|
+.TP
|
||
|
+.B /proc/self/mountstats
|
||
|
+.SH SEE ALSO
|
||
|
+.BR iostat (8),
|
||
|
+.BR mountstats (8),
|
||
|
+.BR nfsstat(8)
|
||
|
+.SH AUTHOR
|
||
|
+Chuck Lever <chuck.lever@oracle.com>
|
||
|
diff -up nfs-utils-1.2.2/tools/nfs-iostat/nfs-iostat.py.orig nfs-utils-1.2.2/tools/nfs-iostat/nfs-iostat.py
|
||
|
--- nfs-utils-1.2.2/tools/nfs-iostat/nfs-iostat.py.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/tools/nfs-iostat/nfs-iostat.py 2010-09-16 16:29:35.241239795 -0400
|
||
|
@@ -366,6 +366,12 @@ class DeviceData:
|
||
|
sends = float(self.__rpc_data['rpcsends'])
|
||
|
if sample_time == 0:
|
||
|
sample_time = float(self.__nfs_data['age'])
|
||
|
+ # sample_time could still be zero if the export was just mounted.
|
||
|
+ # Set it to 1 to avoid divide by zero errors in this case since we'll
|
||
|
+ # likely still have relevant mount statistics to show.
|
||
|
+ #
|
||
|
+ if sample_time == 0:
|
||
|
+ sample_time = 1;
|
||
|
if sends != 0:
|
||
|
backlog = (float(self.__rpc_data['backlogutil']) / sends) / sample_time
|
||
|
else:
|
||
|
diff -up nfs-utils-1.2.2/utils/exportfs/exportfs.c.orig nfs-utils-1.2.2/utils/exportfs/exportfs.c
|
||
|
--- nfs-utils-1.2.2/utils/exportfs/exportfs.c.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/utils/exportfs/exportfs.c 2010-09-16 16:29:35.242230383 -0400
|
||
|
@@ -12,20 +12,24 @@
|
||
|
#include <config.h>
|
||
|
#endif
|
||
|
|
||
|
+#include <sys/types.h>
|
||
|
+#include <sys/stat.h>
|
||
|
#include <sys/vfs.h>
|
||
|
#include <sys/stat.h>
|
||
|
#include <unistd.h>
|
||
|
+#include <stdbool.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
#include <stdarg.h>
|
||
|
#include <getopt.h>
|
||
|
+#include <fcntl.h>
|
||
|
#include <netdb.h>
|
||
|
#include <errno.h>
|
||
|
-#include "xmalloc.h"
|
||
|
+
|
||
|
+#include "sockaddr.h"
|
||
|
#include "misc.h"
|
||
|
#include "nfslib.h"
|
||
|
#include "exportfs.h"
|
||
|
-#include "xmalloc.h"
|
||
|
#include "xlog.h"
|
||
|
|
||
|
static void export_all(int verbose);
|
||
|
@@ -34,13 +38,15 @@ static void unexportfs(char *arg, int ve
|
||
|
static void exports_update(int verbose);
|
||
|
static void dump(int verbose);
|
||
|
static void error(nfs_export *exp, int err);
|
||
|
-static void usage(void);
|
||
|
+static void usage(const char *progname);
|
||
|
static void validate_export(nfs_export *exp);
|
||
|
+static int matchhostname(const char *hostname1, const char *hostname2);
|
||
|
|
||
|
int
|
||
|
main(int argc, char **argv)
|
||
|
{
|
||
|
char *options = NULL;
|
||
|
+ char *progname = NULL;
|
||
|
int f_export = 1;
|
||
|
int f_all = 0;
|
||
|
int f_verbose = 0;
|
||
|
@@ -50,7 +56,14 @@ main(int argc, char **argv)
|
||
|
int new_cache = 0;
|
||
|
int force_flush = 0;
|
||
|
|
||
|
- xlog_open("exportfs");
|
||
|
+ if ((progname = strrchr(argv[0], '/')) != NULL)
|
||
|
+ progname++;
|
||
|
+ else
|
||
|
+ progname = argv[0];
|
||
|
+
|
||
|
+ xlog_open(progname);
|
||
|
+ xlog_stderr(1);
|
||
|
+ xlog_syslog(0);
|
||
|
|
||
|
export_errno = 0;
|
||
|
|
||
|
@@ -79,21 +92,21 @@ main(int argc, char **argv)
|
||
|
force_flush = 1;
|
||
|
break;
|
||
|
default:
|
||
|
- usage();
|
||
|
+ usage(progname);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (optind != argc && f_all) {
|
||
|
- fprintf(stderr,"exportfs: extra arguments are not permitted with -a or -r.\n");
|
||
|
+ xlog(L_ERROR, "extra arguments are not permitted with -a or -r");
|
||
|
return 1;
|
||
|
}
|
||
|
if (f_ignore && (f_all || ! f_export)) {
|
||
|
- fprintf(stderr,"exportfs: -i not meaningful with -a, -r or -u.\n");
|
||
|
+ xlog(L_ERROR, "-i not meaningful with -a, -r or -u");
|
||
|
return 1;
|
||
|
}
|
||
|
if (f_reexport && ! f_export) {
|
||
|
- fprintf(stderr, "exportfs: -r and -u are incompatible.\n");
|
||
|
+ xlog(L_ERROR, "-r and -u are incompatible");
|
||
|
return 1;
|
||
|
}
|
||
|
new_cache = check_new_cache();
|
||
|
@@ -102,8 +115,10 @@ main(int argc, char **argv)
|
||
|
if (new_cache)
|
||
|
cache_flush(1);
|
||
|
else {
|
||
|
- fprintf(stderr, "exportfs: -f: only available with new cache controls: mount /proc/fs/nfsd first\n");
|
||
|
- exit(1);
|
||
|
+ xlog(L_ERROR, "-f is available only "
|
||
|
+ "with new cache controls. "
|
||
|
+ "Mount /proc/fs/nfsd first");
|
||
|
+ return 1;
|
||
|
}
|
||
|
return 0;
|
||
|
} else {
|
||
|
@@ -232,7 +247,7 @@ exportfs(char *arg, char *options, int v
|
||
|
{
|
||
|
struct exportent *eep;
|
||
|
nfs_export *exp;
|
||
|
- struct hostent *hp = NULL;
|
||
|
+ struct addrinfo *ai = NULL;
|
||
|
char *path;
|
||
|
char *hname = arg;
|
||
|
int htype;
|
||
|
@@ -241,36 +256,25 @@ exportfs(char *arg, char *options, int v
|
||
|
*path++ = '\0';
|
||
|
|
||
|
if (!path || *path != '/') {
|
||
|
- fprintf(stderr, "Invalid exporting option: %s\n", arg);
|
||
|
+ xlog(L_ERROR, "Invalid exporting option: %s", arg);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
- if ((htype = client_gettype(hname)) == MCL_FQDN &&
|
||
|
- (hp = gethostbyname(hname)) != NULL) {
|
||
|
- struct hostent *hp2 = hostent_dup (hp);
|
||
|
- hp = gethostbyaddr(hp2->h_addr, hp2->h_length,
|
||
|
- hp2->h_addrtype);
|
||
|
- if (hp) {
|
||
|
- free(hp2);
|
||
|
- hp = hostent_dup(hp);
|
||
|
- } else
|
||
|
- hp = hp2;
|
||
|
- exp = export_find(hp, path);
|
||
|
- hname = hp->h_name;
|
||
|
- } else {
|
||
|
+ if ((htype = client_gettype(hname)) == MCL_FQDN) {
|
||
|
+ ai = host_addrinfo(hname);
|
||
|
+ if (ai != NULL) {
|
||
|
+ exp = export_find(ai, path);
|
||
|
+ hname = ai->ai_canonname;
|
||
|
+ }
|
||
|
+ } else
|
||
|
exp = export_lookup(hname, path, 0);
|
||
|
- }
|
||
|
|
||
|
if (!exp) {
|
||
|
if (!(eep = mkexportent(hname, path, options)) ||
|
||
|
- !(exp = export_create(eep, 0))) {
|
||
|
- if (hp) free (hp);
|
||
|
- return;
|
||
|
- }
|
||
|
- } else if (!updateexportent(&exp->m_export, options)) {
|
||
|
- if (hp) free (hp);
|
||
|
- return;
|
||
|
- }
|
||
|
+ !(exp = export_create(eep, 0)))
|
||
|
+ goto out;
|
||
|
+ } else if (!updateexportent(&exp->m_export, options))
|
||
|
+ goto out;
|
||
|
|
||
|
if (verbose)
|
||
|
printf("exporting %s:%s\n", exp->m_client->m_hostname,
|
||
|
@@ -280,14 +284,16 @@ exportfs(char *arg, char *options, int v
|
||
|
exp->m_changed = 1;
|
||
|
exp->m_warned = 0;
|
||
|
validate_export(exp);
|
||
|
- if (hp) free (hp);
|
||
|
+
|
||
|
+out:
|
||
|
+ freeaddrinfo(ai);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
unexportfs(char *arg, int verbose)
|
||
|
{
|
||
|
nfs_export *exp;
|
||
|
- struct hostent *hp = NULL;
|
||
|
+ struct addrinfo *ai = NULL;
|
||
|
char *path;
|
||
|
char *hname = arg;
|
||
|
int htype;
|
||
|
@@ -296,16 +302,14 @@ unexportfs(char *arg, int verbose)
|
||
|
*path++ = '\0';
|
||
|
|
||
|
if (!path || *path != '/') {
|
||
|
- fprintf(stderr, "Invalid unexporting option: %s\n",
|
||
|
- arg);
|
||
|
+ xlog(L_ERROR, "Invalid unexporting option: %s", arg);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ((htype = client_gettype(hname)) == MCL_FQDN) {
|
||
|
- if ((hp = gethostbyname(hname)) != 0) {
|
||
|
- hp = hostent_dup (hp);
|
||
|
- hname = (char *) hp->h_name;
|
||
|
- }
|
||
|
+ ai = host_addrinfo(hname);
|
||
|
+ if (ai)
|
||
|
+ hname = ai->ai_canonname;
|
||
|
}
|
||
|
|
||
|
for (exp = exportlist[htype].p_head; exp; exp = exp->m_next) {
|
||
|
@@ -341,7 +345,7 @@ unexportfs(char *arg, int verbose)
|
||
|
exp->m_mayexport = 0;
|
||
|
}
|
||
|
|
||
|
- if (hp) free (hp);
|
||
|
+ freeaddrinfo(ai);
|
||
|
}
|
||
|
|
||
|
static int can_test(void)
|
||
|
@@ -393,14 +397,12 @@ validate_export(nfs_export *exp)
|
||
|
int fs_has_fsid = 0;
|
||
|
|
||
|
if (stat(path, &stb) < 0) {
|
||
|
- fprintf(stderr, "exportfs: Warning: %s does not exist\n",
|
||
|
- path);
|
||
|
+ xlog(L_ERROR, "Failed to stat %s: %m \n", path);
|
||
|
return;
|
||
|
}
|
||
|
if (!S_ISDIR(stb.st_mode) && !S_ISREG(stb.st_mode)) {
|
||
|
- fprintf(stderr, "exportfs: Warning: %s is neither "
|
||
|
- "a directory nor a file.\n"
|
||
|
- " remote access will fail\n", path);
|
||
|
+ xlog(L_ERROR, "%s is neither a directory nor a file. "
|
||
|
+ "Remote access will fail", path);
|
||
|
return;
|
||
|
}
|
||
|
if (!can_test())
|
||
|
@@ -413,24 +415,75 @@ validate_export(nfs_export *exp)
|
||
|
if ((exp->m_export.e_flags & NFSEXP_FSID) || exp->m_export.e_uuid ||
|
||
|
fs_has_fsid) {
|
||
|
if ( !test_export(path, 1)) {
|
||
|
- fprintf(stderr, "exportfs: Warning: %s does not "
|
||
|
- "support NFS export.\n",
|
||
|
- path);
|
||
|
+ xlog(L_ERROR, "%s does not support NFS export", path);
|
||
|
return;
|
||
|
}
|
||
|
} else if ( ! test_export(path, 0)) {
|
||
|
if (test_export(path, 1))
|
||
|
- fprintf(stderr, "exportfs: Warning: %s requires fsid= "
|
||
|
- "for NFS export\n", path);
|
||
|
+ xlog(L_ERROR, "%s requires fsid= for NFS export", path);
|
||
|
else
|
||
|
- fprintf(stderr, "exportfs: Warning: %s does not "
|
||
|
- "support NFS export.\n",
|
||
|
- path);
|
||
|
+ xlog(L_ERROR, "%s does not support NFS export", path);
|
||
|
return;
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
+static _Bool
|
||
|
+is_hostname(const char *sp)
|
||
|
+{
|
||
|
+ if (*sp == '\0' || *sp == '@')
|
||
|
+ return false;
|
||
|
+
|
||
|
+ for (; *sp != '\0'; sp++) {
|
||
|
+ if (*sp == '*' || *sp == '?' || *sp == '[' || *sp == '/')
|
||
|
+ return false;
|
||
|
+ if (*sp == '\\' && sp[1] != '\0')
|
||
|
+ sp++;
|
||
|
+ }
|
||
|
+
|
||
|
+ return true;
|
||
|
+}
|
||
|
+
|
||
|
+static int
|
||
|
+matchhostname(const char *hostname1, const char *hostname2)
|
||
|
+{
|
||
|
+ struct addrinfo *results1 = NULL, *results2 = NULL;
|
||
|
+ struct addrinfo *ai1, *ai2;
|
||
|
+ int result = 0;
|
||
|
+
|
||
|
+ if (strcasecmp(hostname1, hostname2) == 0)
|
||
|
+ return 1;
|
||
|
+
|
||
|
+ /*
|
||
|
+ * Don't pass export wildcards or netgroup names to DNS
|
||
|
+ */
|
||
|
+ if (!is_hostname(hostname1) || !is_hostname(hostname2))
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ results1 = host_addrinfo(hostname1);
|
||
|
+ if (results1 == NULL)
|
||
|
+ goto out;
|
||
|
+ results2 = host_addrinfo(hostname2);
|
||
|
+ if (results2 == NULL)
|
||
|
+ goto out;
|
||
|
+
|
||
|
+ if (strcasecmp(results1->ai_canonname, results2->ai_canonname) == 0) {
|
||
|
+ result = 1;
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ for (ai1 = results1; ai1 != NULL; ai1 = ai1->ai_next)
|
||
|
+ for (ai2 = results2; ai2 != NULL; ai2 = ai2->ai_next)
|
||
|
+ if (nfs_compare_sockaddr(ai1->ai_addr, ai2->ai_addr)) {
|
||
|
+ result = 1;
|
||
|
+ break;
|
||
|
+ }
|
||
|
+
|
||
|
+out:
|
||
|
+ freeaddrinfo(results1);
|
||
|
+ freeaddrinfo(results2);
|
||
|
+ return result;
|
||
|
+}
|
||
|
|
||
|
static char
|
||
|
dumpopt(char c, char *fmt, ...)
|
||
|
@@ -532,13 +585,13 @@ dump(int verbose)
|
||
|
static void
|
||
|
error(nfs_export *exp, int err)
|
||
|
{
|
||
|
- fprintf(stderr, "%s:%s: %s\n", exp->m_client->m_hostname,
|
||
|
+ xlog(L_ERROR, "%s:%s: %s\n", exp->m_client->m_hostname,
|
||
|
exp->m_export.e_path, strerror(err));
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
-usage(void)
|
||
|
+usage(const char *progname)
|
||
|
{
|
||
|
- fprintf(stderr, "usage: exportfs [-aruv] [host:/path]\n");
|
||
|
+ fprintf(stderr, "usage: %s [-aruv] [host:/path]\n", progname);
|
||
|
exit(1);
|
||
|
}
|
||
|
diff -up nfs-utils-1.2.2/utils/gssd/context.h.orig nfs-utils-1.2.2/utils/gssd/context.h
|
||
|
--- nfs-utils-1.2.2/utils/gssd/context.h.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/utils/gssd/context.h 2010-09-16 16:29:35.243229775 -0400
|
||
|
@@ -1,5 +1,5 @@
|
||
|
/*
|
||
|
- Copyright (c) 2004 The Regents of the University of Michigan.
|
||
|
+ Copyright (c) 2004,2008 The Regents of the University of Michigan.
|
||
|
All rights reserved.
|
||
|
|
||
|
Redistribution and use in source and binary forms, with or without
|
||
|
@@ -36,6 +36,10 @@
|
||
|
/* Hopefully big enough to hold any serialized context */
|
||
|
#define MAX_CTX_LEN 4096
|
||
|
|
||
|
+/* New context format flag values */
|
||
|
+#define KRB5_CTX_FLAG_INITIATOR 0x00000001
|
||
|
+#define KRB5_CTX_FLAG_CFX 0x00000002
|
||
|
+#define KRB5_CTX_FLAG_ACCEPTOR_SUBKEY 0x00000004
|
||
|
|
||
|
int serialize_context_for_kernel(gss_ctx_id_t ctx, gss_buffer_desc *buf,
|
||
|
gss_OID mech, int32_t *endtime);
|
||
|
diff -up nfs-utils-1.2.2/utils/gssd/context_lucid.c.orig nfs-utils-1.2.2/utils/gssd/context_lucid.c
|
||
|
--- nfs-utils-1.2.2/utils/gssd/context_lucid.c.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/utils/gssd/context_lucid.c 2010-09-16 16:29:35.243229775 -0400
|
||
|
@@ -42,6 +42,7 @@
|
||
|
#include <stdio.h>
|
||
|
#include <syslog.h>
|
||
|
#include <string.h>
|
||
|
+#include <errno.h>
|
||
|
|
||
|
#include <gssapi/gssapi_krb5.h>
|
||
|
|
||
|
@@ -76,7 +77,7 @@ prepare_krb5_rfc1964_buffer(gss_krb5_luc
|
||
|
unsigned char fakeseed[FAKESEED_SIZE];
|
||
|
uint32_t word_send_seq;
|
||
|
gss_krb5_lucid_key_t enc_key;
|
||
|
- int i;
|
||
|
+ uint32_t i;
|
||
|
char *skd, *dkd;
|
||
|
gss_buffer_desc fakeoid;
|
||
|
|
||
|
@@ -119,15 +120,13 @@ prepare_krb5_rfc1964_buffer(gss_krb5_luc
|
||
|
* Note that the rfc1964 version only supports DES enctypes.
|
||
|
*/
|
||
|
if (lctx->rfc1964_kd.ctx_key.type != 4) {
|
||
|
- printerr(1, "prepare_krb5_rfc1964_buffer: "
|
||
|
- "overriding heimdal keytype (%d => %d)\n",
|
||
|
- lctx->rfc1964_kd.ctx_key.type, 4);
|
||
|
+ printerr(2, "%s: overriding heimdal keytype (%d => %d)\n",
|
||
|
+ __FUNCTION__, lctx->rfc1964_kd.ctx_key.type, 4);
|
||
|
lctx->rfc1964_kd.ctx_key.type = 4;
|
||
|
}
|
||
|
#endif
|
||
|
- printerr(2, "prepare_krb5_rfc1964_buffer: serializing keys with "
|
||
|
- "enctype %d and length %d\n",
|
||
|
- lctx->rfc1964_kd.ctx_key.type,
|
||
|
+ printerr(2, "%s: serializing keys with enctype %d and length %d\n",
|
||
|
+ __FUNCTION__, lctx->rfc1964_kd.ctx_key.type,
|
||
|
lctx->rfc1964_kd.ctx_key.length);
|
||
|
|
||
|
/* derive the encryption key and copy it into buffer */
|
||
|
@@ -158,11 +157,102 @@ out_err:
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
+/* Flags for version 2 context flags */
|
||
|
+#define KRB5_CTX_FLAG_INITIATOR 0x00000001
|
||
|
+#define KRB5_CTX_FLAG_CFX 0x00000002
|
||
|
+#define KRB5_CTX_FLAG_ACCEPTOR_SUBKEY 0x00000004
|
||
|
+
|
||
|
+/*
|
||
|
+ * Prepare a new-style buffer, as defined in rfc4121 (a.k.a. cfx),
|
||
|
+ * to send to the kernel for newer encryption types -- or for DES3.
|
||
|
+ *
|
||
|
+ * The new format is:
|
||
|
+ *
|
||
|
+ * u32 flags;
|
||
|
+ * #define KRB5_CTX_FLAG_INITIATOR 0x00000001
|
||
|
+ * #define KRB5_CTX_FLAG_CFX 0x00000002
|
||
|
+ * #define KRB5_CTX_FLAG_ACCEPTOR_SUBKEY 0x00000004
|
||
|
+ * s32 endtime;
|
||
|
+ * u64 seq_send;
|
||
|
+ * u32 enctype; ( encrption type of key )
|
||
|
+ * raw key; ( raw key bytes (kernel will derive))
|
||
|
+ *
|
||
|
+ */
|
||
|
static int
|
||
|
-prepare_krb5_rfc_cfx_buffer(gss_krb5_lucid_context_v1_t *lctx,
|
||
|
+prepare_krb5_rfc4121_buffer(gss_krb5_lucid_context_v1_t *lctx,
|
||
|
gss_buffer_desc *buf, int32_t *endtime)
|
||
|
{
|
||
|
- printerr(0, "ERROR: prepare_krb5_rfc_cfx_buffer: not implemented\n");
|
||
|
+ char *p, *end;
|
||
|
+ uint32_t v2_flags = 0;
|
||
|
+ uint32_t enctype;
|
||
|
+ uint32_t keysize;
|
||
|
+
|
||
|
+ if (!(buf->value = calloc(1, MAX_CTX_LEN)))
|
||
|
+ goto out_err;
|
||
|
+ p = buf->value;
|
||
|
+ end = buf->value + MAX_CTX_LEN;
|
||
|
+
|
||
|
+ /* Version 2 */
|
||
|
+ if (lctx->initiate)
|
||
|
+ v2_flags |= KRB5_CTX_FLAG_INITIATOR;
|
||
|
+ if (lctx->protocol != 0)
|
||
|
+ v2_flags |= KRB5_CTX_FLAG_CFX;
|
||
|
+ if (lctx->protocol != 0 && lctx->cfx_kd.have_acceptor_subkey == 1)
|
||
|
+ v2_flags |= KRB5_CTX_FLAG_ACCEPTOR_SUBKEY;
|
||
|
+
|
||
|
+ if (WRITE_BYTES(&p, end, v2_flags)) goto out_err;
|
||
|
+ if (WRITE_BYTES(&p, end, lctx->endtime)) goto out_err;
|
||
|
+ if (endtime)
|
||
|
+ *endtime = lctx->endtime;
|
||
|
+ if (WRITE_BYTES(&p, end, lctx->send_seq)) goto out_err;
|
||
|
+
|
||
|
+ /* Protocol 0 here implies DES3 or RC4 */
|
||
|
+ printerr(2, "%s: protocol %d\n", __FUNCTION__, lctx->protocol);
|
||
|
+ if (lctx->protocol == 0) {
|
||
|
+ enctype = lctx->rfc1964_kd.ctx_key.type;
|
||
|
+ keysize = lctx->rfc1964_kd.ctx_key.length;
|
||
|
+ } else {
|
||
|
+ if (lctx->cfx_kd.have_acceptor_subkey) {
|
||
|
+ enctype = lctx->cfx_kd.acceptor_subkey.type;
|
||
|
+ keysize = lctx->cfx_kd.acceptor_subkey.length;
|
||
|
+ } else {
|
||
|
+ enctype = lctx->cfx_kd.ctx_key.type;
|
||
|
+ keysize = lctx->cfx_kd.ctx_key.length;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ printerr(2, "%s: serializing key with enctype %d and size %d\n",
|
||
|
+ __FUNCTION__, enctype, keysize);
|
||
|
+
|
||
|
+ if (WRITE_BYTES(&p, end, enctype)) goto out_err;
|
||
|
+
|
||
|
+ if (lctx->protocol == 0) {
|
||
|
+ if (write_bytes(&p, end, lctx->rfc1964_kd.ctx_key.data,
|
||
|
+ lctx->rfc1964_kd.ctx_key.length))
|
||
|
+ goto out_err;
|
||
|
+ } else {
|
||
|
+ if (lctx->cfx_kd.have_acceptor_subkey) {
|
||
|
+ if (write_bytes(&p, end,
|
||
|
+ lctx->cfx_kd.acceptor_subkey.data,
|
||
|
+ lctx->cfx_kd.acceptor_subkey.length))
|
||
|
+ goto out_err;
|
||
|
+ } else {
|
||
|
+ if (write_bytes(&p, end, lctx->cfx_kd.ctx_key.data,
|
||
|
+ lctx->cfx_kd.ctx_key.length))
|
||
|
+ goto out_err;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ buf->length = p - (char *)buf->value;
|
||
|
+ return 0;
|
||
|
+
|
||
|
+out_err:
|
||
|
+ printerr(0, "ERROR: %s: failed serializing krb5 context for kernel\n",
|
||
|
+ __FUNCTION__);
|
||
|
+ if (buf->value) {
|
||
|
+ free(buf->value);
|
||
|
+ buf->value = NULL;
|
||
|
+ }
|
||
|
+ buf->length = 0;
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
@@ -176,7 +266,7 @@ serialize_krb5_ctx(gss_ctx_id_t ctx, gss
|
||
|
gss_krb5_lucid_context_v1_t *lctx = 0;
|
||
|
int retcode = 0;
|
||
|
|
||
|
- printerr(2, "DEBUG: serialize_krb5_ctx: lucid version!\n");
|
||
|
+ printerr(2, "DEBUG: %s: lucid version!\n", __FUNCTION__);
|
||
|
maj_stat = gss_export_lucid_sec_context(&min_stat, &ctx,
|
||
|
1, &return_ctx);
|
||
|
if (maj_stat != GSS_S_COMPLETE) {
|
||
|
@@ -198,11 +288,20 @@ serialize_krb5_ctx(gss_ctx_id_t ctx, gss
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
- /* Now lctx points to a lucid context that we can send down to kernel */
|
||
|
- if (lctx->protocol == 0)
|
||
|
+ /*
|
||
|
+ * Now lctx points to a lucid context that we can send down to kernel
|
||
|
+ *
|
||
|
+ * Note: we send down different information to the kernel depending
|
||
|
+ * on the protocol version and the enctyption type.
|
||
|
+ * For protocol version 0 with all enctypes besides DES3, we use
|
||
|
+ * the original format. For protocol version != 0 or DES3, we
|
||
|
+ * send down the new style information.
|
||
|
+ */
|
||
|
+
|
||
|
+ if (lctx->protocol == 0 && lctx->rfc1964_kd.ctx_key.type <= 4)
|
||
|
retcode = prepare_krb5_rfc1964_buffer(lctx, buf, endtime);
|
||
|
else
|
||
|
- retcode = prepare_krb5_rfc_cfx_buffer(lctx, buf, endtime);
|
||
|
+ retcode = prepare_krb5_rfc4121_buffer(lctx, buf, endtime);
|
||
|
|
||
|
maj_stat = gss_free_lucid_sec_context(&min_stat, ctx, return_ctx);
|
||
|
if (maj_stat != GSS_S_COMPLETE) {
|
||
|
@@ -212,8 +311,8 @@ serialize_krb5_ctx(gss_ctx_id_t ctx, gss
|
||
|
}
|
||
|
|
||
|
if (retcode) {
|
||
|
- printerr(1, "serialize_krb5_ctx: prepare_krb5_*_buffer "
|
||
|
- "failed (retcode = %d)\n", retcode);
|
||
|
+ printerr(1, "%s: prepare_krb5_*_buffer failed (retcode = %d)\n",
|
||
|
+ __FUNCTION__, retcode);
|
||
|
goto out_err;
|
||
|
}
|
||
|
|
||
|
@@ -223,4 +322,7 @@ out_err:
|
||
|
printerr(0, "ERROR: failed serializing krb5 context for kernel\n");
|
||
|
return -1;
|
||
|
}
|
||
|
+
|
||
|
+
|
||
|
+
|
||
|
#endif /* HAVE_LUCID_CONTEXT_SUPPORT */
|
||
|
diff -up nfs-utils-1.2.2/utils/gssd/context_mit.c.orig nfs-utils-1.2.2/utils/gssd/context_mit.c
|
||
|
--- nfs-utils-1.2.2/utils/gssd/context_mit.c.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/utils/gssd/context_mit.c 2010-09-16 16:29:35.244230359 -0400
|
||
|
@@ -1,5 +1,5 @@
|
||
|
/*
|
||
|
- Copyright (c) 2004 The Regents of the University of Michigan.
|
||
|
+ Copyright (c) 2004-2006 The Regents of the University of Michigan.
|
||
|
All rights reserved.
|
||
|
|
||
|
Redistribution and use in source and binary forms, with or without
|
||
|
@@ -38,6 +38,7 @@
|
||
|
#include <stdio.h>
|
||
|
#include <syslog.h>
|
||
|
#include <string.h>
|
||
|
+#include <errno.h>
|
||
|
#include <gssapi/gssapi.h>
|
||
|
#include <rpc/rpc.h>
|
||
|
#include <rpc/auth_gss.h>
|
||
|
@@ -52,8 +53,7 @@
|
||
|
/* XXX argggg, there's gotta be a better way than just duplicating this
|
||
|
* whole struct. Unfortunately, this is in a "private" header file,
|
||
|
* so this is our best choice at this point :-/
|
||
|
- *
|
||
|
- * XXX Does this match the Heimdal definition? */
|
||
|
+ */
|
||
|
|
||
|
typedef struct _krb5_gss_ctx_id_rec {
|
||
|
unsigned int initiate : 1; /* nonzero if initiating, zero if accepting */
|
||
|
@@ -156,50 +156,122 @@ serialize_krb5_ctx(gss_ctx_id_t ctx, gss
|
||
|
{
|
||
|
krb5_gss_ctx_id_t kctx = ((gss_union_ctx_id_t)ctx)->internal_ctx_id;
|
||
|
char *p, *end;
|
||
|
- static int constant_one = 1;
|
||
|
static int constant_zero = 0;
|
||
|
+ static int constant_one = 1;
|
||
|
+ static int constant_two = 2;
|
||
|
uint32_t word_seq_send;
|
||
|
+ u_int64_t seq_send_64bit;
|
||
|
+ uint32_t v2_flags = 0;
|
||
|
|
||
|
if (!(buf->value = calloc(1, MAX_CTX_LEN)))
|
||
|
goto out_err;
|
||
|
p = buf->value;
|
||
|
end = buf->value + MAX_CTX_LEN;
|
||
|
|
||
|
- if (kctx->initiate) {
|
||
|
- if (WRITE_BYTES(&p, end, constant_one)) goto out_err;
|
||
|
- }
|
||
|
- else {
|
||
|
- if (WRITE_BYTES(&p, end, constant_zero)) goto out_err;
|
||
|
- }
|
||
|
- if (kctx->seed_init) {
|
||
|
- if (WRITE_BYTES(&p, end, constant_one)) goto out_err;
|
||
|
- }
|
||
|
- else {
|
||
|
- if (WRITE_BYTES(&p, end, constant_zero)) goto out_err;
|
||
|
- }
|
||
|
- if (write_bytes(&p, end, &kctx->seed, sizeof(kctx->seed)))
|
||
|
+ switch (kctx->enc->enctype) {
|
||
|
+ case ENCTYPE_DES_CBC_CRC:
|
||
|
+ case ENCTYPE_DES_CBC_MD4:
|
||
|
+ case ENCTYPE_DES_CBC_MD5:
|
||
|
+ case ENCTYPE_DES_CBC_RAW:
|
||
|
+ /* Old format of context to the kernel */
|
||
|
+ if (kctx->initiate) {
|
||
|
+ if (WRITE_BYTES(&p, end, constant_one)) goto out_err;
|
||
|
+ }
|
||
|
+ else {
|
||
|
+ if (WRITE_BYTES(&p, end, constant_zero)) goto out_err;
|
||
|
+ }
|
||
|
+ if (kctx->seed_init) {
|
||
|
+ if (WRITE_BYTES(&p, end, constant_one)) goto out_err;
|
||
|
+ }
|
||
|
+ else {
|
||
|
+ if (WRITE_BYTES(&p, end, constant_zero)) goto out_err;
|
||
|
+ }
|
||
|
+ if (write_bytes(&p, end, &kctx->seed, sizeof(kctx->seed)))
|
||
|
+ goto out_err;
|
||
|
+ if (WRITE_BYTES(&p, end, kctx->signalg)) goto out_err;
|
||
|
+ if (WRITE_BYTES(&p, end, kctx->sealalg)) goto out_err;
|
||
|
+ if (WRITE_BYTES(&p, end, kctx->endtime)) goto out_err;
|
||
|
+ if (endtime)
|
||
|
+ *endtime = kctx->endtime;
|
||
|
+ word_seq_send = kctx->seq_send;
|
||
|
+ if (WRITE_BYTES(&p, end, word_seq_send)) goto out_err;
|
||
|
+ if (write_oid(&p, end, kctx->mech_used)) goto out_err;
|
||
|
+
|
||
|
+ printerr(2, "serialize_krb5_ctx: serializing keys with "
|
||
|
+ "enctype %d and length %d\n",
|
||
|
+ kctx->enc->enctype, kctx->enc->length);
|
||
|
+
|
||
|
+ if (write_keyblock(&p, end, kctx->enc)) goto out_err;
|
||
|
+ if (write_keyblock(&p, end, kctx->seq)) goto out_err;
|
||
|
+ break;
|
||
|
+ case ENCTYPE_DES3_CBC_RAW:
|
||
|
+ case ENCTYPE_DES3_CBC_SHA1:
|
||
|
+ case ENCTYPE_ARCFOUR_HMAC:
|
||
|
+ case ENCTYPE_ARCFOUR_HMAC_EXP:
|
||
|
+ case ENCTYPE_AES128_CTS_HMAC_SHA1_96:
|
||
|
+ case ENCTYPE_AES256_CTS_HMAC_SHA1_96:
|
||
|
+ /* New format of context to the kernel */
|
||
|
+ /* u32 flags;
|
||
|
+ * #define KRB5_CTX_FLAG_INITIATOR 0x00000001
|
||
|
+ * #define KRB5_CTX_FLAG_CFX 0x00000002
|
||
|
+ * #define KRB5_CTX_FLAG_ACCEPTOR_SUBKEY 0x00000004
|
||
|
+ * s32 endtime;
|
||
|
+ * u64 seq_send;
|
||
|
+ * u32 enctype;
|
||
|
+ * rawkey data
|
||
|
+ */
|
||
|
+
|
||
|
+ if (kctx->initiate)
|
||
|
+ v2_flags |= KRB5_CTX_FLAG_INITIATOR;
|
||
|
+ if (kctx->proto == 1)
|
||
|
+ v2_flags |= KRB5_CTX_FLAG_CFX;
|
||
|
+ if (kctx->have_acceptor_subkey)
|
||
|
+ v2_flags |= KRB5_CTX_FLAG_ACCEPTOR_SUBKEY;
|
||
|
+ if (WRITE_BYTES(&p, end, v2_flags)) goto out_err;
|
||
|
+ if (WRITE_BYTES(&p, end, kctx->endtime)) goto out_err;
|
||
|
+
|
||
|
+ seq_send_64bit = kctx->seq_send;
|
||
|
+ if (WRITE_BYTES(&p, end, seq_send_64bit)) goto out_err;
|
||
|
+
|
||
|
+ if (kctx->have_acceptor_subkey) {
|
||
|
+ if (WRITE_BYTES(&p, end, kctx->acceptor_subkey->enctype))
|
||
|
+ goto out_err;
|
||
|
+ printerr(2, "serialize_krb5_ctx: serializing subkey "
|
||
|
+ "with enctype %d and size %d\n",
|
||
|
+ kctx->acceptor_subkey->enctype,
|
||
|
+ kctx->acceptor_subkey->length);
|
||
|
+
|
||
|
+ if (write_bytes(&p, end,
|
||
|
+ kctx->acceptor_subkey->contents,
|
||
|
+ kctx->acceptor_subkey->length))
|
||
|
+ goto out_err;
|
||
|
+ } else {
|
||
|
+ if (WRITE_BYTES(&p, end, kctx->enc->enctype))
|
||
|
+ goto out_err;
|
||
|
+ printerr(2, "serialize_krb5_ctx: serializing key "
|
||
|
+ "with enctype %d and size %d\n",
|
||
|
+ kctx->enc->enctype, kctx->enc->length);
|
||
|
+
|
||
|
+ if (write_bytes(&p, end, kctx->enc->contents,
|
||
|
+ kctx->enc->length))
|
||
|
+ goto out_err;
|
||
|
+ }
|
||
|
+ break;
|
||
|
+ default:
|
||
|
+ printerr(0, "ERROR: serialize_krb5_ctx: unsupported encryption "
|
||
|
+ "algorithm %d\n", kctx->enc->enctype);
|
||
|
goto out_err;
|
||
|
- if (WRITE_BYTES(&p, end, kctx->signalg)) goto out_err;
|
||
|
- if (WRITE_BYTES(&p, end, kctx->sealalg)) goto out_err;
|
||
|
- if (WRITE_BYTES(&p, end, kctx->endtime)) goto out_err;
|
||
|
- if (endtime)
|
||
|
- *endtime = kctx->endtime;
|
||
|
- word_seq_send = kctx->seq_send;
|
||
|
- if (WRITE_BYTES(&p, end, word_seq_send)) goto out_err;
|
||
|
- if (write_oid(&p, end, kctx->mech_used)) goto out_err;
|
||
|
-
|
||
|
- printerr(2, "serialize_krb5_ctx: serializing keys with "
|
||
|
- "enctype %d and length %d\n",
|
||
|
- kctx->enc->enctype, kctx->enc->length);
|
||
|
-
|
||
|
- if (write_keyblock(&p, end, kctx->enc)) goto out_err;
|
||
|
- if (write_keyblock(&p, end, kctx->seq)) goto out_err;
|
||
|
+ }
|
||
|
|
||
|
buf->length = p - (char *)buf->value;
|
||
|
return 0;
|
||
|
+
|
||
|
out_err:
|
||
|
printerr(0, "ERROR: failed serializing krb5 context for kernel\n");
|
||
|
- if (buf->value) free(buf->value);
|
||
|
+ if (buf->value) {
|
||
|
+ free(buf->value);
|
||
|
+ }
|
||
|
+ buf->value = NULL;
|
||
|
buf->length = 0;
|
||
|
return -1;
|
||
|
}
|
||
|
diff -up nfs-utils-1.2.2/utils/gssd/gssd.c.orig nfs-utils-1.2.2/utils/gssd/gssd.c
|
||
|
--- nfs-utils-1.2.2/utils/gssd/gssd.c.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/utils/gssd/gssd.c 2010-09-16 16:29:35.245220304 -0400
|
||
|
@@ -78,7 +78,7 @@ void
|
||
|
sig_hup(int signal)
|
||
|
{
|
||
|
/* don't exit on SIGHUP */
|
||
|
- printerr(1, "Received SIGHUP... Ignoring.\n");
|
||
|
+ printerr(1, "Received SIGHUP(%d)... Ignoring.\n", signal);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
diff -up nfs-utils-1.2.2/utils/gssd/gssd_main_loop.c.orig nfs-utils-1.2.2/utils/gssd/gssd_main_loop.c
|
||
|
--- nfs-utils-1.2.2/utils/gssd/gssd_main_loop.c.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/utils/gssd/gssd_main_loop.c 2010-09-16 16:29:35.245220304 -0400
|
||
|
@@ -63,6 +63,8 @@ static volatile int dir_changed = 1;
|
||
|
|
||
|
static void dir_notify_handler(int sig, siginfo_t *si, void *data)
|
||
|
{
|
||
|
+ printerr(2, "dir_notify_handler: sig %d si %p data %p\n", sig, si, data);
|
||
|
+
|
||
|
dir_changed = 1;
|
||
|
}
|
||
|
|
||
|
diff -up nfs-utils-1.2.2/utils/gssd/gssd_proc.c.orig nfs-utils-1.2.2/utils/gssd/gssd_proc.c
|
||
|
--- nfs-utils-1.2.2/utils/gssd/gssd_proc.c.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/utils/gssd/gssd_proc.c 2010-09-16 16:29:35.246249932 -0400
|
||
|
@@ -600,6 +600,67 @@ update_client_list(void)
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
+/* Encryption types supported by the kernel rpcsec_gss code */
|
||
|
+int num_krb5_enctypes = 0;
|
||
|
+krb5_enctype *krb5_enctypes = NULL;
|
||
|
+
|
||
|
+/*
|
||
|
+ * Parse the supported encryption type information
|
||
|
+ */
|
||
|
+static int
|
||
|
+parse_enctypes(char *enctypes)
|
||
|
+{
|
||
|
+ int n = 0;
|
||
|
+ char *curr, *comma;
|
||
|
+ int i;
|
||
|
+ static char *cached_types;
|
||
|
+
|
||
|
+ if (cached_types && strcmp(cached_types, enctypes) == 0)
|
||
|
+ return 0;
|
||
|
+ free(cached_types);
|
||
|
+
|
||
|
+ if (krb5_enctypes != NULL) {
|
||
|
+ free(krb5_enctypes);
|
||
|
+ krb5_enctypes = NULL;
|
||
|
+ num_krb5_enctypes = 0;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* count the number of commas */
|
||
|
+ for (curr = enctypes; curr && *curr != '\0'; curr = ++comma) {
|
||
|
+ comma = strchr(curr, ',');
|
||
|
+ if (comma != NULL)
|
||
|
+ n++;
|
||
|
+ else
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ /* If no more commas and we're not at the end, there's one more value */
|
||
|
+ if (*curr != '\0')
|
||
|
+ n++;
|
||
|
+
|
||
|
+ /* Empty string, return an error */
|
||
|
+ if (n == 0)
|
||
|
+ return ENOENT;
|
||
|
+
|
||
|
+ /* Allocate space for enctypes array */
|
||
|
+ if ((krb5_enctypes = (int *) calloc(n, sizeof(int))) == NULL) {
|
||
|
+ return ENOMEM;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* Now parse each value into the array */
|
||
|
+ for (curr = enctypes, i = 0; curr && *curr != '\0'; curr = ++comma) {
|
||
|
+ krb5_enctypes[i++] = atoi(curr);
|
||
|
+ comma = strchr(curr, ',');
|
||
|
+ if (comma == NULL)
|
||
|
+ break;
|
||
|
+ }
|
||
|
+
|
||
|
+ num_krb5_enctypes = n;
|
||
|
+ if ((cached_types = malloc(strlen(enctypes)+1)))
|
||
|
+ strcpy(cached_types, enctypes);
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
static int
|
||
|
do_downcall(int k5_fd, uid_t uid, struct authgss_private_data *pd,
|
||
|
gss_buffer_desc *context_token)
|
||
|
@@ -798,7 +859,7 @@ int create_auth_rpc_client(struct clnt_i
|
||
|
* Do this before creating rpc connection since we won't need
|
||
|
* rpc connection if it fails!
|
||
|
*/
|
||
|
- if (limit_krb5_enctypes(&sec, uid)) {
|
||
|
+ if (limit_krb5_enctypes(&sec)) {
|
||
|
printerr(1, "WARNING: Failed while limiting krb5 "
|
||
|
"encryption types for user with uid %d\n",
|
||
|
uid);
|
||
|
@@ -875,7 +936,7 @@ int create_auth_rpc_client(struct clnt_i
|
||
|
if (sec.cred != GSS_C_NO_CREDENTIAL)
|
||
|
gss_release_cred(&min_stat, &sec.cred);
|
||
|
/* Restore euid to original value */
|
||
|
- if ((save_uid != -1) && (setfsuid(save_uid) != uid)) {
|
||
|
+ if (((int)save_uid != -1) && (setfsuid(save_uid) != (int)uid)) {
|
||
|
printerr(0, "WARNING: Failed to restore fsuid"
|
||
|
" to uid %d from %d\n", save_uid, uid);
|
||
|
}
|
||
|
@@ -1100,7 +1161,7 @@ handle_krb5_upcall(struct clnt_info *clp
|
||
|
{
|
||
|
uid_t uid;
|
||
|
|
||
|
- if (read(clp->krb5_fd, &uid, sizeof(uid)) < sizeof(uid)) {
|
||
|
+ if (read(clp->krb5_fd, &uid, sizeof(uid)) < (ssize_t)sizeof(uid)) {
|
||
|
printerr(0, "WARNING: failed reading uid from krb5 "
|
||
|
"upcall pipe: %s\n", strerror(errno));
|
||
|
return;
|
||
|
@@ -1114,7 +1175,7 @@ handle_spkm3_upcall(struct clnt_info *cl
|
||
|
{
|
||
|
uid_t uid;
|
||
|
|
||
|
- if (read(clp->spkm3_fd, &uid, sizeof(uid)) < sizeof(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;
|
||
|
@@ -1133,6 +1194,7 @@ handle_gssd_upcall(struct clnt_info *clp
|
||
|
char *mech = NULL;
|
||
|
char *target = NULL;
|
||
|
char *service = NULL;
|
||
|
+ char *enctypes = NULL;
|
||
|
|
||
|
printerr(1, "handling gssd upcall (%s)\n", clp->dirname);
|
||
|
|
||
|
@@ -1176,6 +1238,23 @@ handle_gssd_upcall(struct clnt_info *clp
|
||
|
goto out;
|
||
|
}
|
||
|
|
||
|
+ /* read supported encryption types if supplied */
|
||
|
+ if ((p = strstr(lbuf, "enctypes=")) != NULL) {
|
||
|
+ enctypes = malloc(lbuflen);
|
||
|
+ if (!enctypes)
|
||
|
+ goto out;
|
||
|
+ if (sscanf(p, "enctypes=%s", enctypes) != 1) {
|
||
|
+ printerr(0, "WARNING: handle_gssd_upcall: "
|
||
|
+ "failed to parse target name "
|
||
|
+ "in upcall string '%s'\n", lbuf);
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+ if (parse_enctypes(enctypes) != 0) {
|
||
|
+ printerr(0, "WARNING: handle_gssd_upcall: "
|
||
|
+ "parsing encryption types failed: errno %d\n", errno);
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
/* read target name */
|
||
|
if ((p = strstr(lbuf, "target=")) != NULL) {
|
||
|
target = malloc(lbuflen);
|
||
|
@@ -1222,6 +1301,7 @@ handle_gssd_upcall(struct clnt_info *clp
|
||
|
out:
|
||
|
free(lbuf);
|
||
|
free(mech);
|
||
|
+ free(enctypes);
|
||
|
free(target);
|
||
|
free(service);
|
||
|
return;
|
||
|
diff -up nfs-utils-1.2.2/utils/gssd/krb5_util.c.orig nfs-utils-1.2.2/utils/gssd/krb5_util.c
|
||
|
--- nfs-utils-1.2.2/utils/gssd/krb5_util.c.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/utils/gssd/krb5_util.c 2010-09-16 16:29:35.247230807 -0400
|
||
|
@@ -224,6 +224,13 @@ gssd_find_existing_krb5_ccache(uid_t uid
|
||
|
free(namelist[i]);
|
||
|
continue;
|
||
|
}
|
||
|
+ if (uid == 0 && !root_uses_machine_creds &&
|
||
|
+ strstr(namelist[i]->d_name, "_machine_")) {
|
||
|
+ printerr(3, "CC file '%s' not available to root\n",
|
||
|
+ statname);
|
||
|
+ free(namelist[i]);
|
||
|
+ continue;
|
||
|
+ }
|
||
|
if (!query_krb5_ccache(buf, &princname, &realm)) {
|
||
|
printerr(3, "CC file '%s' is expired or corrupt\n",
|
||
|
statname);
|
||
|
@@ -292,61 +299,6 @@ gssd_find_existing_krb5_ccache(uid_t uid
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
-
|
||
|
-#ifdef HAVE_SET_ALLOWABLE_ENCTYPES
|
||
|
-/*
|
||
|
- * this routine obtains a credentials handle via gss_acquire_cred()
|
||
|
- * then calls gss_krb5_set_allowable_enctypes() to limit the encryption
|
||
|
- * types negotiated.
|
||
|
- *
|
||
|
- * XXX Should call some function to determine the enctypes supported
|
||
|
- * by the kernel. (Only need to do that once!)
|
||
|
- *
|
||
|
- * Returns:
|
||
|
- * 0 => all went well
|
||
|
- * -1 => there was an error
|
||
|
- */
|
||
|
-
|
||
|
-int
|
||
|
-limit_krb5_enctypes(struct rpc_gss_sec *sec, uid_t uid)
|
||
|
-{
|
||
|
- u_int maj_stat, min_stat;
|
||
|
- gss_cred_id_t credh;
|
||
|
- gss_OID_set_desc desired_mechs;
|
||
|
- krb5_enctype enctypes[] = { ENCTYPE_DES_CBC_CRC,
|
||
|
- ENCTYPE_DES_CBC_MD5,
|
||
|
- ENCTYPE_DES_CBC_MD4 };
|
||
|
- int num_enctypes = sizeof(enctypes) / sizeof(enctypes[0]);
|
||
|
-
|
||
|
- /* We only care about getting a krb5 cred */
|
||
|
- desired_mechs.count = 1;
|
||
|
- desired_mechs.elements = &krb5oid;
|
||
|
-
|
||
|
- maj_stat = gss_acquire_cred(&min_stat, NULL, 0,
|
||
|
- &desired_mechs, GSS_C_INITIATE,
|
||
|
- &credh, NULL, NULL);
|
||
|
-
|
||
|
- if (maj_stat != GSS_S_COMPLETE) {
|
||
|
- if (get_verbosity() > 0)
|
||
|
- pgsserr("gss_acquire_cred",
|
||
|
- maj_stat, min_stat, &krb5oid);
|
||
|
- return -1;
|
||
|
- }
|
||
|
-
|
||
|
- maj_stat = gss_set_allowable_enctypes(&min_stat, credh, &krb5oid,
|
||
|
- num_enctypes, &enctypes);
|
||
|
- if (maj_stat != GSS_S_COMPLETE) {
|
||
|
- pgsserr("gss_set_allowable_enctypes",
|
||
|
- maj_stat, min_stat, &krb5oid);
|
||
|
- gss_release_cred(&min_stat, &credh);
|
||
|
- return -1;
|
||
|
- }
|
||
|
- sec->cred = credh;
|
||
|
-
|
||
|
- return 0;
|
||
|
-}
|
||
|
-#endif /* HAVE_SET_ALLOWABLE_ENCTYPES */
|
||
|
-
|
||
|
/*
|
||
|
* Obtain credentials via a key in the keytab given
|
||
|
* a keytab handle and a gssd_k5_kt_princ structure.
|
||
|
@@ -661,24 +613,32 @@ out:
|
||
|
* and has *any* instance (hostname), return 1.
|
||
|
* Otherwise return 0, indicating no match.
|
||
|
*/
|
||
|
+#ifdef HAVE_KRB5
|
||
|
static int
|
||
|
-realm_and_service_match(krb5_context context, krb5_principal p,
|
||
|
- const char *realm, const char *service)
|
||
|
+realm_and_service_match(krb5_principal p, const char *realm, const char *service)
|
||
|
{
|
||
|
-#ifdef HAVE_KRB5
|
||
|
/* Must have two components */
|
||
|
if (p->length != 2)
|
||
|
return 0;
|
||
|
+
|
||
|
if ((strlen(realm) == p->realm.length)
|
||
|
&& (strncmp(realm, p->realm.data, p->realm.length) == 0)
|
||
|
&& (strlen(service) == p->data[0].length)
|
||
|
&& (strncmp(service, p->data[0].data, p->data[0].length) == 0))
|
||
|
return 1;
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
#else
|
||
|
+static int
|
||
|
+realm_and_service_match(krb5_context context, krb5_principal p,
|
||
|
+ const char *realm, const char *service)
|
||
|
+{
|
||
|
const char *name, *inst;
|
||
|
|
||
|
if (p->name.name_string.len != 2)
|
||
|
return 0;
|
||
|
+
|
||
|
name = krb5_principal_get_comp_string(context, p, 0);
|
||
|
inst = krb5_principal_get_comp_string(context, p, 1);
|
||
|
if (name == NULL || inst == NULL)
|
||
|
@@ -686,9 +646,10 @@ realm_and_service_match(krb5_context con
|
||
|
if ((strcmp(realm, p->realm) == 0)
|
||
|
&& (strcmp(service, name) == 0))
|
||
|
return 1;
|
||
|
-#endif
|
||
|
+
|
||
|
return 0;
|
||
|
}
|
||
|
+#endif
|
||
|
|
||
|
/*
|
||
|
* Search the given keytab file looking for an entry with the given
|
||
|
@@ -710,7 +671,7 @@ gssd_search_krb5_keytab(krb5_context con
|
||
|
krb5_kt_cursor cursor;
|
||
|
krb5_error_code code;
|
||
|
struct gssd_k5_kt_princ *ple;
|
||
|
- int retval = -1;
|
||
|
+ int retval = -1, status;
|
||
|
char kt_name[BUFSIZ];
|
||
|
char *pname;
|
||
|
char *k5err = NULL;
|
||
|
@@ -753,8 +714,12 @@ gssd_search_krb5_keytab(krb5_context con
|
||
|
printerr(4, "Processing keytab entry for principal '%s'\n",
|
||
|
pname);
|
||
|
/* Use the first matching keytab entry found */
|
||
|
- if ((realm_and_service_match(context, kte->principal, realm,
|
||
|
- service))) {
|
||
|
+#ifdef HAVE_KRB5
|
||
|
+ status = realm_and_service_match(kte->principal, realm, service);
|
||
|
+#else
|
||
|
+ status = realm_and_service_match(context, kte->principal, realm, service);
|
||
|
+#endif
|
||
|
+ if (status) {
|
||
|
printerr(4, "We WILL use this entry (%s)\n", pname);
|
||
|
ple = get_ple_by_princ(context, kte->principal);
|
||
|
/*
|
||
|
@@ -1304,3 +1269,68 @@ gssd_k5_get_default_realm(char **def_rea
|
||
|
|
||
|
krb5_free_context(context);
|
||
|
}
|
||
|
+
|
||
|
+#ifdef HAVE_SET_ALLOWABLE_ENCTYPES
|
||
|
+/*
|
||
|
+ * this routine obtains a credentials handle via gss_acquire_cred()
|
||
|
+ * then calls gss_krb5_set_allowable_enctypes() to limit the encryption
|
||
|
+ * types negotiated.
|
||
|
+ *
|
||
|
+ * XXX Should call some function to determine the enctypes supported
|
||
|
+ * by the kernel. (Only need to do that once!)
|
||
|
+ *
|
||
|
+ * Returns:
|
||
|
+ * 0 => all went well
|
||
|
+ * -1 => there was an error
|
||
|
+ */
|
||
|
+
|
||
|
+int
|
||
|
+limit_krb5_enctypes(struct rpc_gss_sec *sec)
|
||
|
+{
|
||
|
+ u_int maj_stat, min_stat;
|
||
|
+ gss_cred_id_t credh;
|
||
|
+ gss_OID_set_desc desired_mechs;
|
||
|
+ krb5_enctype enctypes[] = { ENCTYPE_DES_CBC_CRC,
|
||
|
+ ENCTYPE_DES_CBC_MD5,
|
||
|
+ ENCTYPE_DES_CBC_MD4 };
|
||
|
+ int num_enctypes = sizeof(enctypes) / sizeof(enctypes[0]);
|
||
|
+ extern int num_krb5_enctypes;
|
||
|
+ extern krb5_enctype *krb5_enctypes;
|
||
|
+
|
||
|
+ /* We only care about getting a krb5 cred */
|
||
|
+ desired_mechs.count = 1;
|
||
|
+ desired_mechs.elements = &krb5oid;
|
||
|
+
|
||
|
+ maj_stat = gss_acquire_cred(&min_stat, NULL, 0,
|
||
|
+ &desired_mechs, GSS_C_INITIATE,
|
||
|
+ &credh, NULL, NULL);
|
||
|
+
|
||
|
+ if (maj_stat != GSS_S_COMPLETE) {
|
||
|
+ if (get_verbosity() > 0)
|
||
|
+ pgsserr("gss_acquire_cred",
|
||
|
+ maj_stat, min_stat, &krb5oid);
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+
|
||
|
+ /*
|
||
|
+ * If we failed for any reason to produce global
|
||
|
+ * list of supported enctypes, use local default here.
|
||
|
+ */
|
||
|
+ if (krb5_enctypes == NULL)
|
||
|
+ maj_stat = gss_set_allowable_enctypes(&min_stat, credh,
|
||
|
+ &krb5oid, num_enctypes, enctypes);
|
||
|
+ else
|
||
|
+ maj_stat = gss_set_allowable_enctypes(&min_stat, credh,
|
||
|
+ &krb5oid, num_krb5_enctypes, krb5_enctypes);
|
||
|
+
|
||
|
+ if (maj_stat != GSS_S_COMPLETE) {
|
||
|
+ pgsserr("gss_set_allowable_enctypes",
|
||
|
+ maj_stat, min_stat, &krb5oid);
|
||
|
+ gss_release_cred(&min_stat, &credh);
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+ sec->cred = credh;
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+#endif /* HAVE_SET_ALLOWABLE_ENCTYPES */
|
||
|
diff -up nfs-utils-1.2.2/utils/gssd/krb5_util.h.orig nfs-utils-1.2.2/utils/gssd/krb5_util.h
|
||
|
--- nfs-utils-1.2.2/utils/gssd/krb5_util.h.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/utils/gssd/krb5_util.h 2010-09-16 16:29:35.248210613 -0400
|
||
|
@@ -36,7 +36,7 @@ char *gssd_k5_err_msg(krb5_context conte
|
||
|
void gssd_k5_get_default_realm(char **def_realm);
|
||
|
|
||
|
#ifdef HAVE_SET_ALLOWABLE_ENCTYPES
|
||
|
-int limit_krb5_enctypes(struct rpc_gss_sec *sec, uid_t uid);
|
||
|
+int limit_krb5_enctypes(struct rpc_gss_sec *sec);
|
||
|
#endif
|
||
|
|
||
|
/*
|
||
|
diff -up nfs-utils-1.2.2/utils/gssd/svcgssd.c.orig nfs-utils-1.2.2/utils/gssd/svcgssd.c
|
||
|
--- nfs-utils-1.2.2/utils/gssd/svcgssd.c.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/utils/gssd/svcgssd.c 2010-09-16 16:29:35.248210613 -0400
|
||
|
@@ -160,7 +160,7 @@ void
|
||
|
sig_hup(int signal)
|
||
|
{
|
||
|
/* don't exit on SIGHUP */
|
||
|
- printerr(1, "Received SIGHUP... Ignoring.\n");
|
||
|
+ printerr(1, "Received SIGHUP(%d)... Ignoring.\n", signal);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
diff -up nfs-utils-1.2.2/utils/gssd/svcgssd_proc.c.orig nfs-utils-1.2.2/utils/gssd/svcgssd_proc.c
|
||
|
--- nfs-utils-1.2.2/utils/gssd/svcgssd_proc.c.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/utils/gssd/svcgssd_proc.c 2010-09-16 16:29:35.249273951 -0400
|
||
|
@@ -132,7 +132,7 @@ struct gss_verifier {
|
||
|
#define RPCSEC_GSS_SEQ_WIN 5
|
||
|
|
||
|
static int
|
||
|
-send_response(FILE *f, gss_buffer_desc *in_handle, gss_buffer_desc *in_token,
|
||
|
+send_response(gss_buffer_desc *in_handle, gss_buffer_desc *in_token,
|
||
|
u_int32_t maj_stat, u_int32_t min_stat,
|
||
|
gss_buffer_desc *out_handle, gss_buffer_desc *out_token)
|
||
|
{
|
||
|
@@ -431,12 +431,6 @@ handle_nullreq(FILE *f) {
|
||
|
print_hexl("in_tok", in_tok.value, in_tok.length);
|
||
|
#endif
|
||
|
|
||
|
- if (in_tok.length < 0) {
|
||
|
- printerr(0, "WARNING: handle_nullreq: "
|
||
|
- "failed parsing request\n");
|
||
|
- goto out_err;
|
||
|
- }
|
||
|
-
|
||
|
if (in_handle.length != 0) { /* CONTINUE_INIT case */
|
||
|
if (in_handle.length != sizeof(ctx)) {
|
||
|
printerr(0, "WARNING: handle_nullreq: "
|
||
|
@@ -498,7 +492,7 @@ handle_nullreq(FILE *f) {
|
||
|
do_svc_downcall(&out_handle, &cred, mech, &ctx_token, ctx_endtime,
|
||
|
hostbased_name);
|
||
|
continue_needed:
|
||
|
- send_response(f, &in_handle, &in_tok, maj_stat, min_stat,
|
||
|
+ send_response(&in_handle, &in_tok, maj_stat, min_stat,
|
||
|
&out_handle, &out_tok);
|
||
|
out:
|
||
|
if (ctx_token.value != NULL)
|
||
|
@@ -514,7 +508,7 @@ out:
|
||
|
out_err:
|
||
|
if (ctx != GSS_C_NO_CONTEXT)
|
||
|
gss_delete_sec_context(&ignore_min_stat, &ctx, &ignore_out_tok);
|
||
|
- send_response(f, &in_handle, &in_tok, maj_stat, min_stat,
|
||
|
+ send_response(&in_handle, &in_tok, maj_stat, min_stat,
|
||
|
&null_token, &null_token);
|
||
|
goto out;
|
||
|
}
|
||
|
diff -up nfs-utils-1.2.2/utils/idmapd/atomicio.c.orig nfs-utils-1.2.2/utils/idmapd/atomicio.c
|
||
|
--- nfs-utils-1.2.2/utils/idmapd/atomicio.c.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/utils/idmapd/atomicio.c 2010-09-16 16:29:35.250239931 -0400
|
||
|
@@ -43,7 +43,8 @@ atomicio(
|
||
|
size_t n)
|
||
|
{
|
||
|
char *s = _s;
|
||
|
- ssize_t res, pos = 0;
|
||
|
+ ssize_t res;
|
||
|
+ size_t pos = 0;
|
||
|
|
||
|
while (n > pos) {
|
||
|
res = (f) (fd, s + pos, n - pos);
|
||
|
diff -up nfs-utils-1.2.2/utils/idmapd/idmapd.c.orig nfs-utils-1.2.2/utils/idmapd/idmapd.c
|
||
|
--- nfs-utils-1.2.2/utils/idmapd/idmapd.c.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/utils/idmapd/idmapd.c 2010-09-16 16:29:35.250239931 -0400
|
||
|
@@ -117,8 +117,24 @@ struct idmap_client {
|
||
|
TAILQ_ENTRY(idmap_client) ic_next;
|
||
|
};
|
||
|
static struct idmap_client nfsd_ic[2] = {
|
||
|
-{IC_IDNAME, "Server", "", IC_IDNAME_CHAN, -1, -1, 0},
|
||
|
-{IC_NAMEID, "Server", "", IC_NAMEID_CHAN, -1, -1, 0},
|
||
|
+{
|
||
|
+ .ic_which = IC_IDNAME,
|
||
|
+ .ic_clid = "",
|
||
|
+ .ic_id = "Server",
|
||
|
+ .ic_path = IC_IDNAME_CHAN,
|
||
|
+ .ic_fd = -1,
|
||
|
+ .ic_dirfd = -1,
|
||
|
+ .ic_scanned = 0
|
||
|
+},
|
||
|
+{
|
||
|
+ .ic_which = IC_NAMEID,
|
||
|
+ .ic_clid = "",
|
||
|
+ .ic_id = "Server",
|
||
|
+ .ic_path = IC_NAMEID_CHAN,
|
||
|
+ .ic_fd = -1,
|
||
|
+ .ic_dirfd = -1,
|
||
|
+ .ic_scanned = 0
|
||
|
+},
|
||
|
};
|
||
|
|
||
|
TAILQ_HEAD(idmap_clientq, idmap_client);
|
||
|
@@ -170,7 +186,7 @@ flush_nfsd_cache(char *path, time_t now)
|
||
|
fd = open(path, O_RDWR);
|
||
|
if (fd == -1)
|
||
|
return -1;
|
||
|
- if (write(fd, stime, strlen(stime)) != strlen(stime)) {
|
||
|
+ if (write(fd, stime, strlen(stime)) != (ssize_t)strlen(stime)) {
|
||
|
errx(1, "Flushing nfsd cache failed: errno %d (%s)",
|
||
|
errno, strerror(errno));
|
||
|
}
|
||
|
@@ -381,7 +397,7 @@ main(int argc, char **argv)
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
-dirscancb(int fd, short which, void *data)
|
||
|
+dirscancb(int UNUSED(fd), short UNUSED(which), void *data)
|
||
|
{
|
||
|
int nent, i;
|
||
|
struct dirent **ents;
|
||
|
@@ -465,13 +481,13 @@ out:
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
-svrreopen(int fd, short which, void *data)
|
||
|
+svrreopen(int UNUSED(fd), short UNUSED(which), void *UNUSED(data))
|
||
|
{
|
||
|
nfsdreopen();
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
-clntscancb(int fd, short which, void *data)
|
||
|
+clntscancb(int UNUSED(fd), short UNUSED(which), void *data)
|
||
|
{
|
||
|
struct idmap_clientq *icq = data;
|
||
|
struct idmap_client *ic;
|
||
|
@@ -485,7 +501,7 @@ clntscancb(int fd, short which, void *da
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
-nfsdcb(int fd, short which, void *data)
|
||
|
+nfsdcb(int UNUSED(fd), short which, void *data)
|
||
|
{
|
||
|
struct idmap_client *ic = data;
|
||
|
struct idmap_msg im;
|
||
|
@@ -660,7 +676,7 @@ imconv(struct idmap_client *ic, struct i
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
-nfscb(int fd, short which, void *data)
|
||
|
+nfscb(int UNUSED(fd), short which, void *data)
|
||
|
{
|
||
|
struct idmap_client *ic = data;
|
||
|
struct idmap_msg im;
|
||
|
@@ -845,7 +861,7 @@ nametoidres(struct idmap_msg *im)
|
||
|
static int
|
||
|
validateascii(char *string, u_int32_t len)
|
||
|
{
|
||
|
- int i;
|
||
|
+ u_int32_t i;
|
||
|
|
||
|
for (i = 0; i < len; i++) {
|
||
|
if (string[i] == '\0')
|
||
|
@@ -901,7 +917,7 @@ static int
|
||
|
getfield(char **bpp, char *fld, size_t fldsz)
|
||
|
{
|
||
|
char *bp;
|
||
|
- u_int val, n;
|
||
|
+ int val, n;
|
||
|
|
||
|
while ((bp = strsep(bpp, " ")) != NULL && bp[0] == '\0')
|
||
|
;
|
||
|
diff -up nfs-utils-1.2.2/utils/mount/configfile.c.orig nfs-utils-1.2.2/utils/mount/configfile.c
|
||
|
--- nfs-utils-1.2.2/utils/mount/configfile.c.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/utils/mount/configfile.c 2010-09-16 16:29:35.251230426 -0400
|
||
|
@@ -192,7 +192,8 @@ void free_all(void)
|
||
|
}
|
||
|
}
|
||
|
static char *versions[] = {"v2", "v3", "v4", "vers", "nfsvers", NULL};
|
||
|
-int inline check_vers(char *mopt, char *field)
|
||
|
+static int
|
||
|
+check_vers(char *mopt, char *field)
|
||
|
{
|
||
|
int i, found=0;
|
||
|
|
||
|
@@ -229,7 +230,8 @@ extern sa_family_t config_default_family
|
||
|
* If so, set the appropriate global value which will
|
||
|
* be used as the initial value in the server negation.
|
||
|
*/
|
||
|
-int inline default_value(char *mopt)
|
||
|
+static int
|
||
|
+default_value(char *mopt)
|
||
|
{
|
||
|
struct mount_options *options = NULL;
|
||
|
int dftlen = strlen("default");
|
||
|
diff -up nfs-utils-1.2.2/utils/mountd/auth.c.orig nfs-utils-1.2.2/utils/mountd/auth.c
|
||
|
--- nfs-utils-1.2.2/utils/mountd/auth.c.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/utils/mountd/auth.c 2010-09-16 16:29:35.257230538 -0400
|
||
|
@@ -15,6 +15,8 @@
|
||
|
#include <arpa/inet.h>
|
||
|
#include <errno.h>
|
||
|
#include <unistd.h>
|
||
|
+
|
||
|
+#include "sockaddr.h"
|
||
|
#include "misc.h"
|
||
|
#include "nfslib.h"
|
||
|
#include "exportfs.h"
|
||
|
@@ -110,13 +112,16 @@ auth_reload()
|
||
|
return counter;
|
||
|
}
|
||
|
|
||
|
-static char *get_client_hostname(struct sockaddr_in *caller, struct hostent *hp, enum auth_error *error)
|
||
|
+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(inet_ntoa(caller->sin_addr));
|
||
|
- n = client_compose(hp);
|
||
|
+ return strdup(host_ntop(caller, buf, sizeof(buf)));
|
||
|
+ n = client_compose(ai);
|
||
|
*error = unknown_host;
|
||
|
if (!n)
|
||
|
return NULL;
|
||
|
@@ -128,8 +133,8 @@ static char *get_client_hostname(struct
|
||
|
|
||
|
/* return static nfs_export with details filled in */
|
||
|
static nfs_export *
|
||
|
-auth_authenticate_newcache(char *what, struct sockaddr_in *caller,
|
||
|
- char *path, struct hostent *hp,
|
||
|
+auth_authenticate_newcache(const struct sockaddr *caller,
|
||
|
+ const char *path, struct addrinfo *ai,
|
||
|
enum auth_error *error)
|
||
|
{
|
||
|
nfs_export *exp;
|
||
|
@@ -137,12 +142,12 @@ auth_authenticate_newcache(char *what, s
|
||
|
|
||
|
free(my_client.m_hostname);
|
||
|
|
||
|
- my_client.m_hostname = get_client_hostname(caller, hp, error);
|
||
|
+ my_client.m_hostname = get_client_hostname(caller, ai, error);
|
||
|
if (my_client.m_hostname == NULL)
|
||
|
return NULL;
|
||
|
|
||
|
my_client.m_naddr = 1;
|
||
|
- my_client.m_addrlist[0] = caller->sin_addr;
|
||
|
+ set_addrlist(&my_client, 0, caller);
|
||
|
my_exp.m_client = &my_client;
|
||
|
|
||
|
exp = NULL;
|
||
|
@@ -152,7 +157,7 @@ auth_authenticate_newcache(char *what, s
|
||
|
continue;
|
||
|
if (!use_ipaddr && !client_member(my_client.m_hostname, exp->m_client->m_hostname))
|
||
|
continue;
|
||
|
- if (use_ipaddr && !client_check(exp->m_client, hp))
|
||
|
+ if (use_ipaddr && !client_check(exp->m_client, ai))
|
||
|
continue;
|
||
|
break;
|
||
|
}
|
||
|
@@ -166,18 +171,18 @@ auth_authenticate_newcache(char *what, s
|
||
|
}
|
||
|
|
||
|
static nfs_export *
|
||
|
-auth_authenticate_internal(char *what, struct sockaddr_in *caller,
|
||
|
- char *path, struct hostent *hp,
|
||
|
- enum auth_error *error)
|
||
|
+auth_authenticate_internal(const struct sockaddr *caller, const char *path,
|
||
|
+ struct addrinfo *ai, enum auth_error *error)
|
||
|
{
|
||
|
nfs_export *exp;
|
||
|
|
||
|
if (new_cache) {
|
||
|
- exp = auth_authenticate_newcache(what, caller, path, hp, error);
|
||
|
+ exp = auth_authenticate_newcache(caller, path, ai, error);
|
||
|
if (!exp)
|
||
|
return NULL;
|
||
|
} else {
|
||
|
- if (!(exp = export_find(hp, path))) {
|
||
|
+ exp = export_find(ai, path);
|
||
|
+ if (exp == NULL) {
|
||
|
*error = no_entry;
|
||
|
return NULL;
|
||
|
}
|
||
|
@@ -187,7 +192,7 @@ auth_authenticate_internal(char *what, s
|
||
|
return NULL;
|
||
|
}
|
||
|
if (!(exp->m_export.e_flags & NFSEXP_INSECURE_PORT) &&
|
||
|
- ntohs(caller->sin_port) >= IPPORT_RESERVED) {
|
||
|
+ nfs_get_port(caller) >= IPPORT_RESERVED) {
|
||
|
*error = illegal_port;
|
||
|
return NULL;
|
||
|
}
|
||
|
@@ -197,18 +202,19 @@ auth_authenticate_internal(char *what, s
|
||
|
}
|
||
|
|
||
|
nfs_export *
|
||
|
-auth_authenticate(char *what, struct sockaddr_in *caller, char *path)
|
||
|
+auth_authenticate(const char *what, const struct sockaddr *caller,
|
||
|
+ const char *path)
|
||
|
{
|
||
|
nfs_export *exp = NULL;
|
||
|
char epath[MAXPATHLEN+1];
|
||
|
char *p = NULL;
|
||
|
- struct hostent *hp = NULL;
|
||
|
- struct in_addr addr = caller->sin_addr;
|
||
|
+ char buf[INET6_ADDRSTRLEN];
|
||
|
+ struct addrinfo *ai = NULL;
|
||
|
enum auth_error error = bad_path;
|
||
|
|
||
|
- if (path [0] != '/') {
|
||
|
- xlog(L_WARNING, "bad path in %s request from %s: \"%s\"",
|
||
|
- what, inet_ntoa(addr), path);
|
||
|
+ if (path[0] != '/') {
|
||
|
+ xlog(L_WARNING, "Bad path in %s request from %s: \"%s\"",
|
||
|
+ what, host_ntop(caller, buf, sizeof(buf)), path);
|
||
|
return exp;
|
||
|
}
|
||
|
|
||
|
@@ -216,14 +222,13 @@ auth_authenticate(char *what, struct soc
|
||
|
epath[sizeof (epath) - 1] = '\0';
|
||
|
auth_fixpath(epath); /* strip duplicate '/' etc */
|
||
|
|
||
|
- hp = client_resolve(caller->sin_addr);
|
||
|
- if (!hp)
|
||
|
+ ai = client_resolve(caller);
|
||
|
+ if (ai == NULL)
|
||
|
return exp;
|
||
|
|
||
|
/* Try the longest matching exported pathname. */
|
||
|
while (1) {
|
||
|
- exp = auth_authenticate_internal(what, caller, epath,
|
||
|
- hp, &error);
|
||
|
+ exp = auth_authenticate_internal(caller, epath, ai, &error);
|
||
|
if (exp || (error != not_exported && error != no_entry))
|
||
|
break;
|
||
|
/* We have to treat the root, "/", specially. */
|
||
|
@@ -236,41 +241,40 @@ auth_authenticate(char *what, struct soc
|
||
|
switch (error) {
|
||
|
case bad_path:
|
||
|
xlog(L_WARNING, "bad path in %s request from %s: \"%s\"",
|
||
|
- what, inet_ntoa(addr), path);
|
||
|
+ what, host_ntop(caller, buf, sizeof(buf)), path);
|
||
|
break;
|
||
|
|
||
|
case unknown_host:
|
||
|
xlog(L_WARNING, "refused %s request from %s for %s (%s): unmatched host",
|
||
|
- what, inet_ntoa(addr), path, epath);
|
||
|
+ what, host_ntop(caller, buf, sizeof(buf)), path, epath);
|
||
|
break;
|
||
|
|
||
|
case no_entry:
|
||
|
xlog(L_WARNING, "refused %s request from %s for %s (%s): no export entry",
|
||
|
- what, hp->h_name, path, epath);
|
||
|
+ what, ai->ai_canonname, path, epath);
|
||
|
break;
|
||
|
|
||
|
case not_exported:
|
||
|
xlog(L_WARNING, "refused %s request from %s for %s (%s): not exported",
|
||
|
- what, hp->h_name, path, epath);
|
||
|
+ what, ai->ai_canonname, path, epath);
|
||
|
break;
|
||
|
|
||
|
case illegal_port:
|
||
|
- xlog(L_WARNING, "refused %s request from %s for %s (%s): illegal port %d",
|
||
|
- what, hp->h_name, path, epath, ntohs(caller->sin_port));
|
||
|
+ xlog(L_WARNING, "refused %s request from %s for %s (%s): illegal port %u",
|
||
|
+ what, ai->ai_canonname, path, epath, nfs_get_port(caller));
|
||
|
break;
|
||
|
|
||
|
case success:
|
||
|
- xlog(L_NOTICE, "authenticated %s request from %s:%d for %s (%s)",
|
||
|
- what, hp->h_name, ntohs(caller->sin_port), path, epath);
|
||
|
+ xlog(L_NOTICE, "authenticated %s request from %s:%u for %s (%s)",
|
||
|
+ what, ai->ai_canonname, nfs_get_port(caller), path, epath);
|
||
|
break;
|
||
|
default:
|
||
|
- xlog(L_NOTICE, "%s request from %s:%d for %s (%s) gave %d",
|
||
|
- what, hp->h_name, ntohs(caller->sin_port), path, epath, error);
|
||
|
+ xlog(L_NOTICE, "%s request from %s:%u for %s (%s) gave %d",
|
||
|
+ what, ai->ai_canonname, nfs_get_port(caller),
|
||
|
+ path, epath, error);
|
||
|
}
|
||
|
|
||
|
- if (hp)
|
||
|
- free (hp);
|
||
|
-
|
||
|
+ freeaddrinfo(ai);
|
||
|
return exp;
|
||
|
}
|
||
|
|
||
|
diff -up nfs-utils-1.2.2/utils/mountd/cache.c.orig nfs-utils-1.2.2/utils/mountd/cache.c
|
||
|
--- nfs-utils-1.2.2/utils/mountd/cache.c.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/utils/mountd/cache.c 2010-09-16 16:29:35.258229814 -0400
|
||
|
@@ -37,6 +37,11 @@
|
||
|
#include "blkid/blkid.h"
|
||
|
#endif
|
||
|
|
||
|
+/*
|
||
|
+ * Invoked by RPC service loop
|
||
|
+ */
|
||
|
+void cache_set_fds(fd_set *fdset);
|
||
|
+int cache_process_req(fd_set *readfds);
|
||
|
|
||
|
enum nfsd_fsid {
|
||
|
FSID_DEV = 0,
|
||
|
@@ -57,14 +62,14 @@ enum nfsd_fsid {
|
||
|
* Record is terminated with newline.
|
||
|
*
|
||
|
*/
|
||
|
-int cache_export_ent(char *domain, struct exportent *exp, char *p);
|
||
|
+static int cache_export_ent(char *domain, struct exportent *exp, char *p);
|
||
|
|
||
|
|
||
|
char *lbuf = NULL;
|
||
|
int lbuflen = 0;
|
||
|
extern int use_ipaddr;
|
||
|
|
||
|
-void auth_unix_ip(FILE *f)
|
||
|
+static void auth_unix_ip(FILE *f)
|
||
|
{
|
||
|
/* requests are
|
||
|
* class IP-ADDR
|
||
|
@@ -75,10 +80,10 @@ void auth_unix_ip(FILE *f)
|
||
|
*/
|
||
|
char *cp;
|
||
|
char class[20];
|
||
|
- char ipaddr[20];
|
||
|
+ char ipaddr[INET6_ADDRSTRLEN];
|
||
|
char *client = NULL;
|
||
|
- struct in_addr addr;
|
||
|
- struct hostent *he = NULL;
|
||
|
+ struct addrinfo *tmp = NULL;
|
||
|
+ struct addrinfo *ai = NULL;
|
||
|
if (readline(fileno(f), &lbuf, &lbuflen) != 1)
|
||
|
return;
|
||
|
|
||
|
@@ -90,20 +95,23 @@ void auth_unix_ip(FILE *f)
|
||
|
strcmp(class, "nfsd") != 0)
|
||
|
return;
|
||
|
|
||
|
- if (qword_get(&cp, ipaddr, 20) <= 0)
|
||
|
+ if (qword_get(&cp, ipaddr, sizeof(ipaddr)) <= 0)
|
||
|
return;
|
||
|
|
||
|
- if (inet_aton(ipaddr, &addr)==0)
|
||
|
+ tmp = host_pton(ipaddr);
|
||
|
+ if (tmp == NULL)
|
||
|
return;
|
||
|
|
||
|
auth_reload();
|
||
|
|
||
|
/* addr is a valid, interesting address, find the domain name... */
|
||
|
if (!use_ipaddr) {
|
||
|
- he = client_resolve(addr);
|
||
|
- client = client_compose(he);
|
||
|
+ ai = client_resolve(tmp->ai_addr);
|
||
|
+ client = client_compose(ai);
|
||
|
+ freeaddrinfo(ai);
|
||
|
}
|
||
|
-
|
||
|
+ freeaddrinfo(tmp);
|
||
|
+
|
||
|
qword_print(f, "nfsd");
|
||
|
qword_print(f, ipaddr);
|
||
|
qword_printint(f, time(0)+30*60);
|
||
|
@@ -114,18 +122,17 @@ void auth_unix_ip(FILE *f)
|
||
|
qword_eol(f);
|
||
|
xlog(D_CALL, "auth_unix_ip: client %p '%s'", client, client?client: "DEFAULT");
|
||
|
|
||
|
- if (client) free(client);
|
||
|
- free(he);
|
||
|
+ free(client);
|
||
|
}
|
||
|
|
||
|
-void auth_unix_gid(FILE *f)
|
||
|
+static void auth_unix_gid(FILE *f)
|
||
|
{
|
||
|
/* Request are
|
||
|
* uid
|
||
|
* reply is
|
||
|
* uid expiry count list of group ids
|
||
|
*/
|
||
|
- int uid;
|
||
|
+ uid_t uid;
|
||
|
struct passwd *pw;
|
||
|
gid_t glist[100], *groups = glist;
|
||
|
int ngroups = 100;
|
||
|
@@ -136,7 +143,7 @@ void auth_unix_gid(FILE *f)
|
||
|
return;
|
||
|
|
||
|
cp = lbuf;
|
||
|
- if (qword_get_int(&cp, &uid) != 0)
|
||
|
+ if (qword_get_uint(&cp, &uid) != 0)
|
||
|
return;
|
||
|
|
||
|
pw = getpwuid(uid);
|
||
|
@@ -153,14 +160,14 @@ void auth_unix_gid(FILE *f)
|
||
|
groups, &ngroups);
|
||
|
}
|
||
|
}
|
||
|
- qword_printint(f, uid);
|
||
|
- qword_printint(f, time(0)+30*60);
|
||
|
+ qword_printuint(f, uid);
|
||
|
+ qword_printuint(f, time(0)+30*60);
|
||
|
if (rv >= 0) {
|
||
|
- qword_printint(f, ngroups);
|
||
|
+ qword_printuint(f, ngroups);
|
||
|
for (i=0; i<ngroups; i++)
|
||
|
- qword_printint(f, groups[i]);
|
||
|
+ qword_printuint(f, groups[i]);
|
||
|
} else
|
||
|
- qword_printint(f, 0);
|
||
|
+ qword_printuint(f, 0);
|
||
|
qword_eol(f);
|
||
|
|
||
|
if (groups != glist)
|
||
|
@@ -170,13 +177,16 @@ void auth_unix_gid(FILE *f)
|
||
|
#if USE_BLKID
|
||
|
static const char *get_uuid_blkdev(char *path)
|
||
|
{
|
||
|
+ /* We set *safe if we know that we need the
|
||
|
+ * fsid from statfs too.
|
||
|
+ */
|
||
|
static blkid_cache cache = NULL;
|
||
|
struct stat stb;
|
||
|
char *devname;
|
||
|
blkid_tag_iterate iter;
|
||
|
blkid_dev dev;
|
||
|
const char *type;
|
||
|
- const char *val = NULL;
|
||
|
+ const char *val, *uuid = NULL;
|
||
|
|
||
|
if (cache == NULL)
|
||
|
blkid_get_cache(&cache, NULL);
|
||
|
@@ -193,42 +203,29 @@ static const char *get_uuid_blkdev(char
|
||
|
iter = blkid_tag_iterate_begin(dev);
|
||
|
if (!iter)
|
||
|
return NULL;
|
||
|
- while (blkid_tag_next(iter, &type, &val) == 0)
|
||
|
+ while (blkid_tag_next(iter, &type, &val) == 0) {
|
||
|
if (strcmp(type, "UUID") == 0)
|
||
|
+ uuid = val;
|
||
|
+ if (strcmp(type, "TYPE") == 0 &&
|
||
|
+ strcmp(val, "btrfs") == 0) {
|
||
|
+ uuid = NULL;
|
||
|
break;
|
||
|
+ }
|
||
|
+ }
|
||
|
blkid_tag_iterate_end(iter);
|
||
|
- return val;
|
||
|
+ return uuid;
|
||
|
}
|
||
|
#else
|
||
|
#define get_uuid_blkdev(path) (NULL)
|
||
|
#endif
|
||
|
|
||
|
-int get_uuid(char *path, char *uuid, int uuidlen, char *u)
|
||
|
+static int get_uuid(const char *val, int uuidlen, char *u)
|
||
|
{
|
||
|
/* extract hex digits from uuidstr and compose a uuid
|
||
|
* of the given length (max 16), xoring bytes to make
|
||
|
- * a smaller uuid. Then compare with uuid
|
||
|
+ * a smaller uuid.
|
||
|
*/
|
||
|
int i = 0;
|
||
|
- const char *val = NULL;
|
||
|
- char fsid_val[17];
|
||
|
-
|
||
|
- if (path) {
|
||
|
- val = get_uuid_blkdev(path);
|
||
|
- if (!val) {
|
||
|
- struct statfs64 st;
|
||
|
-
|
||
|
- if (statfs64(path, &st))
|
||
|
- return 0;
|
||
|
- if (!st.f_fsid.__val[0] && !st.f_fsid.__val[1])
|
||
|
- return 0;
|
||
|
- snprintf(fsid_val, 17, "%08x%08x",
|
||
|
- st.f_fsid.__val[0], st.f_fsid.__val[1]);
|
||
|
- val = fsid_val;
|
||
|
- }
|
||
|
- } else {
|
||
|
- val = uuid;
|
||
|
- }
|
||
|
|
||
|
memset(u, 0, uuidlen);
|
||
|
for ( ; *val ; val++) {
|
||
|
@@ -252,6 +249,60 @@ int get_uuid(char *path, char *uuid, int
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
+static int uuid_by_path(char *path, int type, int uuidlen, char *uuid)
|
||
|
+{
|
||
|
+ /* get a uuid for the filesystem found at 'path'.
|
||
|
+ * There are several possible ways of generating the
|
||
|
+ * uuids (types).
|
||
|
+ * Type 0 is used for new filehandles, while other types
|
||
|
+ * may be used to interpret old filehandle - to ensure smooth
|
||
|
+ * forward migration.
|
||
|
+ * We return 1 if a uuid was found (and it might be worth
|
||
|
+ * trying the next type) or 0 if no more uuid types can be
|
||
|
+ * extracted.
|
||
|
+ */
|
||
|
+
|
||
|
+ /* Possible sources of uuid are
|
||
|
+ * - blkid uuid
|
||
|
+ * - statfs64 uuid
|
||
|
+ *
|
||
|
+ * On some filesystems (e.g. vfat) the statfs64 uuid is simply an
|
||
|
+ * encoding of the device that the filesystem is mounted from, so
|
||
|
+ * it we be very bad to use that (as device numbers change). blkid
|
||
|
+ * must be preferred.
|
||
|
+ * On other filesystems (e.g. btrfs) the statfs64 uuid contains
|
||
|
+ * important info that the blkid uuid cannot contain: This happens
|
||
|
+ * when multiple subvolumes are exported (they have the same
|
||
|
+ * blkid uuid but different statfs64 uuids).
|
||
|
+ * We rely on get_uuid_blkdev *knowing* which is which and not returning
|
||
|
+ * a uuid for filesystems where the statfs64 uuid is better.
|
||
|
+ *
|
||
|
+ */
|
||
|
+ struct statfs64 st;
|
||
|
+ char fsid_val[17];
|
||
|
+ const char *blkid_val;
|
||
|
+ const char *val;
|
||
|
+
|
||
|
+ blkid_val = get_uuid_blkdev(path);
|
||
|
+
|
||
|
+ if (statfs64(path, &st) == 0 &&
|
||
|
+ (st.f_fsid.__val[0] || st.f_fsid.__val[1]))
|
||
|
+ snprintf(fsid_val, 17, "%08x%08x",
|
||
|
+ st.f_fsid.__val[0], st.f_fsid.__val[1]);
|
||
|
+ else
|
||
|
+ fsid_val[0] = 0;
|
||
|
+
|
||
|
+ if (blkid_val && (type--) == 0)
|
||
|
+ val = blkid_val;
|
||
|
+ else if (fsid_val[0] && (type--) == 0)
|
||
|
+ val = fsid_val;
|
||
|
+ else
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ get_uuid(val, uuidlen, uuid);
|
||
|
+ return 1;
|
||
|
+}
|
||
|
+
|
||
|
/* Iterate through /etc/mtab, finding mountpoints
|
||
|
* at or below a given path
|
||
|
*/
|
||
|
@@ -277,7 +328,7 @@ static char *next_mnt(void **v, char *p)
|
||
|
return me->mnt_dir;
|
||
|
}
|
||
|
|
||
|
-void nfsd_fh(FILE *f)
|
||
|
+static void nfsd_fh(FILE *f)
|
||
|
{
|
||
|
/* request are:
|
||
|
* domain fsidtype fsid
|
||
|
@@ -294,8 +345,7 @@ void nfsd_fh(FILE *f)
|
||
|
unsigned int fsidnum=0;
|
||
|
char fsid[32];
|
||
|
struct exportent *found = NULL;
|
||
|
- struct hostent *he = NULL;
|
||
|
- struct in_addr addr;
|
||
|
+ struct addrinfo *ai = NULL;
|
||
|
char *found_path = NULL;
|
||
|
nfs_export *exp;
|
||
|
int i;
|
||
|
@@ -398,6 +448,7 @@ void nfsd_fh(FILE *f)
|
||
|
struct stat stb;
|
||
|
char u[16];
|
||
|
char *path;
|
||
|
+ int type;
|
||
|
|
||
|
if (exp->m_export.e_flags & NFSEXP_CROSSMOUNT) {
|
||
|
static nfs_export *prev = NULL;
|
||
|
@@ -461,22 +512,29 @@ void nfsd_fh(FILE *f)
|
||
|
continue;
|
||
|
check_uuid:
|
||
|
if (exp->m_export.e_uuid)
|
||
|
- get_uuid(NULL, exp->m_export.e_uuid,
|
||
|
+ get_uuid(exp->m_export.e_uuid,
|
||
|
uuidlen, u);
|
||
|
- else if (get_uuid(path, NULL, uuidlen, u) == 0)
|
||
|
- continue;
|
||
|
+ else
|
||
|
+ for (type = 0;
|
||
|
+ uuid_by_path(path, type, uuidlen, u);
|
||
|
+ type++)
|
||
|
+ if (memcmp(u, fhuuid, uuidlen) == 0)
|
||
|
+ break;
|
||
|
|
||
|
if (memcmp(u, fhuuid, uuidlen) != 0)
|
||
|
continue;
|
||
|
break;
|
||
|
}
|
||
|
if (use_ipaddr) {
|
||
|
- if (he == NULL) {
|
||
|
- if (!inet_aton(dom, &addr))
|
||
|
+ if (ai == NULL) {
|
||
|
+ struct addrinfo *tmp;
|
||
|
+ tmp = host_pton(dom);
|
||
|
+ if (tmp == NULL)
|
||
|
goto out;
|
||
|
- he = client_resolve(addr);
|
||
|
+ ai = client_resolve(tmp->ai_addr);
|
||
|
+ freeaddrinfo(tmp);
|
||
|
}
|
||
|
- if (!client_check(exp->m_client, he))
|
||
|
+ if (!client_check(exp->m_client, ai))
|
||
|
continue;
|
||
|
}
|
||
|
/* It's a match !! */
|
||
|
@@ -534,21 +592,20 @@ void nfsd_fh(FILE *f)
|
||
|
out:
|
||
|
if (found_path)
|
||
|
free(found_path);
|
||
|
- if (he)
|
||
|
- free(he);
|
||
|
+ freeaddrinfo(ai);
|
||
|
free(dom);
|
||
|
xlog(D_CALL, "nfsd_fh: found %p path %s", found, found ? found->e_path : NULL);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
-static void write_fsloc(FILE *f, struct exportent *ep, char *path)
|
||
|
+static void write_fsloc(FILE *f, struct exportent *ep)
|
||
|
{
|
||
|
struct servers *servers;
|
||
|
|
||
|
if (ep->e_fslocmethod == FSLOC_NONE)
|
||
|
return;
|
||
|
|
||
|
- servers = replicas_lookup(ep->e_fslocmethod, ep->e_fslocdata, path);
|
||
|
+ servers = replicas_lookup(ep->e_fslocmethod, ep->e_fslocdata);
|
||
|
if (!servers)
|
||
|
return;
|
||
|
qword_print(f, "fsloc");
|
||
|
@@ -596,17 +653,17 @@ static int dump_to_cache(FILE *f, char *
|
||
|
qword_printint(f, exp->e_anonuid);
|
||
|
qword_printint(f, exp->e_anongid);
|
||
|
qword_printint(f, exp->e_fsid);
|
||
|
- write_fsloc(f, exp, path);
|
||
|
+ write_fsloc(f, exp);
|
||
|
write_secinfo(f, exp, flag_mask);
|
||
|
if (exp->e_uuid == NULL || different_fs) {
|
||
|
char u[16];
|
||
|
- if (get_uuid(path, NULL, 16, u)) {
|
||
|
+ if (uuid_by_path(path, 0, 16, u)) {
|
||
|
qword_print(f, "uuid");
|
||
|
qword_printhex(f, u, 16);
|
||
|
}
|
||
|
} else {
|
||
|
char u[16];
|
||
|
- get_uuid(NULL, exp->e_uuid, 16, u);
|
||
|
+ get_uuid(exp->e_uuid, 16, u);
|
||
|
qword_print(f, "uuid");
|
||
|
qword_printhex(f, u, 16);
|
||
|
}
|
||
|
@@ -614,12 +671,12 @@ static int dump_to_cache(FILE *f, char *
|
||
|
return qword_eol(f);
|
||
|
}
|
||
|
|
||
|
-static int is_subdirectory(char *subpath, char *path)
|
||
|
+static int is_subdirectory(char *child, char *parent)
|
||
|
{
|
||
|
- int l = strlen(path);
|
||
|
+ int l = strlen(parent);
|
||
|
|
||
|
- return strcmp(subpath, path) == 0
|
||
|
- || (strncmp(subpath, path, l) == 0 && path[l] == '/');
|
||
|
+ return strcmp(child, parent) == 0
|
||
|
+ || (strncmp(child, parent, l) == 0 && child[l] == '/');
|
||
|
}
|
||
|
|
||
|
static int path_matches(nfs_export *exp, char *path)
|
||
|
@@ -629,19 +686,22 @@ static int path_matches(nfs_export *exp,
|
||
|
return strcmp(path, exp->m_export.e_path) == 0;
|
||
|
}
|
||
|
|
||
|
-static int client_matches(nfs_export *exp, char *dom, struct hostent *he)
|
||
|
+static int
|
||
|
+client_matches(nfs_export *exp, char *dom, struct addrinfo *ai)
|
||
|
{
|
||
|
if (use_ipaddr)
|
||
|
- return client_check(exp->m_client, he);
|
||
|
+ 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 hostent *he)
|
||
|
+static int
|
||
|
+export_matches(nfs_export *exp, char *dom, char *path, struct addrinfo *ai)
|
||
|
{
|
||
|
- return path_matches(exp, path) && client_matches(exp, dom, he);
|
||
|
+ return path_matches(exp, path) && client_matches(exp, dom, ai);
|
||
|
}
|
||
|
|
||
|
-static nfs_export *lookup_export(char *dom, char *path, struct hostent *he)
|
||
|
+static nfs_export *
|
||
|
+lookup_export(char *dom, char *path, struct addrinfo *ai)
|
||
|
{
|
||
|
nfs_export *exp;
|
||
|
nfs_export *found = NULL;
|
||
|
@@ -650,7 +710,7 @@ static nfs_export *lookup_export(char *d
|
||
|
|
||
|
for (i=0 ; i < MCL_MAXTYPES; i++) {
|
||
|
for (exp = exportlist[i].p_head; exp; exp = exp->m_next) {
|
||
|
- if (!export_matches(exp, dom, path, he))
|
||
|
+ if (!export_matches(exp, dom, path, ai))
|
||
|
continue;
|
||
|
if (!found) {
|
||
|
found = exp;
|
||
|
@@ -687,7 +747,7 @@ static nfs_export *lookup_export(char *d
|
||
|
return found;
|
||
|
}
|
||
|
|
||
|
-void nfsd_export(FILE *f)
|
||
|
+static void nfsd_export(FILE *f)
|
||
|
{
|
||
|
/* requests are:
|
||
|
* domain path
|
||
|
@@ -698,9 +758,7 @@ void nfsd_export(FILE *f)
|
||
|
char *cp;
|
||
|
char *dom, *path;
|
||
|
nfs_export *found = NULL;
|
||
|
- struct in_addr addr;
|
||
|
- struct hostent *he = NULL;
|
||
|
-
|
||
|
+ struct addrinfo *ai = NULL;
|
||
|
|
||
|
if (readline(fileno(f), &lbuf, &lbuflen) != 1)
|
||
|
return;
|
||
|
@@ -722,12 +780,16 @@ void nfsd_export(FILE *f)
|
||
|
auth_reload();
|
||
|
|
||
|
if (use_ipaddr) {
|
||
|
- if (!inet_aton(dom, &addr))
|
||
|
+ struct addrinfo *tmp;
|
||
|
+ tmp = host_pton(dom);
|
||
|
+ if (tmp == NULL)
|
||
|
+ goto out;
|
||
|
+ ai = client_resolve(tmp->ai_addr);
|
||
|
+ freeaddrinfo(tmp);
|
||
|
goto out;
|
||
|
- he = client_resolve(addr);
|
||
|
}
|
||
|
|
||
|
- found = lookup_export(dom, path, he);
|
||
|
+ found = lookup_export(dom, path, ai);
|
||
|
|
||
|
if (found) {
|
||
|
if (dump_to_cache(f, dom, path, &found->m_export) < 0) {
|
||
|
@@ -743,7 +805,7 @@ void nfsd_export(FILE *f)
|
||
|
xlog(D_CALL, "nfsd_export: found %p path %s", found, path ? path : NULL);
|
||
|
if (dom) free(dom);
|
||
|
if (path) free(path);
|
||
|
- if (he) free(he);
|
||
|
+ freeaddrinfo(ai);
|
||
|
}
|
||
|
|
||
|
|
||
|
@@ -752,14 +814,19 @@ struct {
|
||
|
void (*cache_handle)(FILE *f);
|
||
|
FILE *f;
|
||
|
} cachelist[] = {
|
||
|
- { "auth.unix.ip", auth_unix_ip},
|
||
|
- { "auth.unix.gid", auth_unix_gid},
|
||
|
- { "nfsd.export", nfsd_export},
|
||
|
- { "nfsd.fh", nfsd_fh},
|
||
|
- { NULL, NULL }
|
||
|
+ { "auth.unix.ip", auth_unix_ip, NULL},
|
||
|
+ { "auth.unix.gid", auth_unix_gid, NULL},
|
||
|
+ { "nfsd.export", nfsd_export, NULL},
|
||
|
+ { "nfsd.fh", nfsd_fh, NULL},
|
||
|
+ { NULL, NULL, NULL }
|
||
|
};
|
||
|
|
||
|
extern int manage_gids;
|
||
|
+
|
||
|
+/**
|
||
|
+ * cache_open - prepare communications channels with kernel RPC caches
|
||
|
+ *
|
||
|
+ */
|
||
|
void cache_open(void)
|
||
|
{
|
||
|
int i;
|
||
|
@@ -772,6 +839,10 @@ void cache_open(void)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
+/**
|
||
|
+ * cache_set_fds - prepare cache file descriptors for one iteration of the service loop
|
||
|
+ * @fdset: pointer to fd_set to prepare
|
||
|
+ */
|
||
|
void cache_set_fds(fd_set *fdset)
|
||
|
{
|
||
|
int i;
|
||
|
@@ -781,6 +852,10 @@ void cache_set_fds(fd_set *fdset)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
+/**
|
||
|
+ * cache_process_req - process any active cache file descriptors during service loop iteration
|
||
|
+ * @fdset: pointer to fd_set to examine for activity
|
||
|
+ */
|
||
|
int cache_process_req(fd_set *readfds)
|
||
|
{
|
||
|
int i;
|
||
|
@@ -803,7 +878,7 @@ int cache_process_req(fd_set *readfds)
|
||
|
* % echo $domain $path $[now+30*60] $options $anonuid $anongid $fsid > /proc/net/rpc/nfsd.export/channel
|
||
|
*/
|
||
|
|
||
|
-int cache_export_ent(char *domain, struct exportent *exp, char *path)
|
||
|
+static int cache_export_ent(char *domain, struct exportent *exp, char *path)
|
||
|
{
|
||
|
int err;
|
||
|
FILE *f = fopen("/proc/net/rpc/nfsd.export/channel", "w");
|
||
|
@@ -824,8 +899,8 @@ int cache_export_ent(char *domain, struc
|
||
|
* and export them with the same options
|
||
|
*/
|
||
|
struct stat stb;
|
||
|
- int l = strlen(exp->e_path);
|
||
|
- int dev;
|
||
|
+ size_t l = strlen(exp->e_path);
|
||
|
+ __dev_t dev;
|
||
|
|
||
|
if (strlen(path) <= l || path[l] != '/' ||
|
||
|
strncmp(exp->e_path, path, l) != 0)
|
||
|
@@ -861,8 +936,14 @@ int cache_export_ent(char *domain, struc
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
+/**
|
||
|
+ * cache_export - Inform kernel of a new nfs_export
|
||
|
+ * @exp: target nfs_export
|
||
|
+ * @path: NUL-terminated C string containing export path
|
||
|
+ */
|
||
|
int cache_export(nfs_export *exp, char *path)
|
||
|
{
|
||
|
+ char buf[INET6_ADDRSTRLEN];
|
||
|
int err;
|
||
|
FILE *f;
|
||
|
|
||
|
@@ -870,8 +951,10 @@ int cache_export(nfs_export *exp, char *
|
||
|
if (!f)
|
||
|
return -1;
|
||
|
|
||
|
+
|
||
|
qword_print(f, "nfsd");
|
||
|
- qword_print(f, inet_ntoa(exp->m_client->m_addrlist[0]));
|
||
|
+ qword_print(f,
|
||
|
+ host_ntop(get_addrlist(exp->m_client, 0), buf, sizeof(buf)));
|
||
|
qword_printint(f, time(0)+30*60);
|
||
|
qword_print(f, exp->m_client->m_hostname);
|
||
|
err = qword_eol(f);
|
||
|
@@ -883,7 +966,14 @@ int cache_export(nfs_export *exp, char *
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
-/* Get a filehandle.
|
||
|
+/**
|
||
|
+ * cache_get_filehandle - given an nfs_export, get its root filehandle
|
||
|
+ * @exp: target nfs_export
|
||
|
+ * @len: length of requested file handle
|
||
|
+ * @p: NUL-terminated C string containing export path
|
||
|
+ *
|
||
|
+ * Returns pointer to NFS file handle of root directory of export
|
||
|
+ *
|
||
|
* {
|
||
|
* echo $domain $path $length
|
||
|
* read filehandle <&0
|
||
|
@@ -917,4 +1007,3 @@ cache_get_filehandle(nfs_export *exp, in
|
||
|
fh.fh_size = qword_get(&bp, (char *)fh.fh_handle, NFS3_FHSIZE);
|
||
|
return &fh;
|
||
|
}
|
||
|
-
|
||
|
diff -up nfs-utils-1.2.2/utils/mountd/fsloc.c.orig nfs-utils-1.2.2/utils/mountd/fsloc.c
|
||
|
--- nfs-utils-1.2.2/utils/mountd/fsloc.c.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/utils/mountd/fsloc.c 2010-09-16 16:29:35.259209794 -0400
|
||
|
@@ -146,7 +146,7 @@ static struct servers *method_list(char
|
||
|
}
|
||
|
|
||
|
/* Returns appropriately filled struct servers, or NULL if had a problem */
|
||
|
-struct servers *replicas_lookup(int method, char *data, char *key)
|
||
|
+struct servers *replicas_lookup(int method, char *data)
|
||
|
{
|
||
|
struct servers *sp=NULL;
|
||
|
switch(method) {
|
||
|
diff -up nfs-utils-1.2.2/utils/mountd/fsloc.h.orig nfs-utils-1.2.2/utils/mountd/fsloc.h
|
||
|
--- nfs-utils-1.2.2/utils/mountd/fsloc.h.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/utils/mountd/fsloc.h 2010-09-16 16:29:35.260229826 -0400
|
||
|
@@ -44,7 +44,7 @@ struct servers {
|
||
|
int h_referral; /* 0=replica, 1=referral */
|
||
|
};
|
||
|
|
||
|
-struct servers *replicas_lookup(int method, char *data, char *key);
|
||
|
+struct servers *replicas_lookup(int method, char *data);
|
||
|
void release_replicas(struct servers *server);
|
||
|
|
||
|
#endif /* FSLOC_H */
|
||
|
diff -up nfs-utils-1.2.2/utils/mountd/mountd.c.orig nfs-utils-1.2.2/utils/mountd/mountd.c
|
||
|
--- nfs-utils-1.2.2/utils/mountd/mountd.c.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/utils/mountd/mountd.c 2010-09-16 16:29:35.260229826 -0400
|
||
|
@@ -28,10 +28,6 @@
|
||
|
#include "rpcmisc.h"
|
||
|
#include "pseudoflavors.h"
|
||
|
|
||
|
-extern void cache_open(void);
|
||
|
-extern struct nfs_fh_len *cache_get_filehandle(nfs_export *exp, int len, char *p);
|
||
|
-extern int cache_export(nfs_export *exp, char *path);
|
||
|
-
|
||
|
extern void my_svc_run(void);
|
||
|
|
||
|
static void usage(const char *, int exitcode);
|
||
|
@@ -80,10 +76,10 @@ static int nfs_version = -1;
|
||
|
static void
|
||
|
unregister_services (void)
|
||
|
{
|
||
|
- if (nfs_version & 0x1)
|
||
|
+ if (nfs_version & (0x1 << 1)) {
|
||
|
pmap_unset (MOUNTPROG, MOUNTVERS);
|
||
|
- if (nfs_version & (0x1 << 1))
|
||
|
pmap_unset (MOUNTPROG, MOUNTVERS_POSIX);
|
||
|
+ }
|
||
|
if (nfs_version & (0x1 << 2))
|
||
|
pmap_unset (MOUNTPROG, MOUNTVERS_NFSV3);
|
||
|
}
|
||
|
@@ -192,17 +188,28 @@ sig_hup (int sig)
|
||
|
}
|
||
|
|
||
|
bool_t
|
||
|
-mount_null_1_svc(struct svc_req *rqstp, void *argp, void *resp)
|
||
|
+mount_null_1_svc(struct svc_req *rqstp, void *UNUSED(argp),
|
||
|
+ void *UNUSED(resp))
|
||
|
{
|
||
|
+ struct sockaddr *sap = nfs_getrpccaller(rqstp->rq_xprt);
|
||
|
+ char buf[INET6_ADDRSTRLEN];
|
||
|
+
|
||
|
+ xlog(D_CALL, "Received NULL request from %s",
|
||
|
+ host_ntop(sap, buf, sizeof(buf)));
|
||
|
+
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
bool_t
|
||
|
mount_mnt_1_svc(struct svc_req *rqstp, dirpath *path, fhstatus *res)
|
||
|
{
|
||
|
+ struct sockaddr *sap = nfs_getrpccaller(rqstp->rq_xprt);
|
||
|
+ char buf[INET6_ADDRSTRLEN];
|
||
|
struct nfs_fh_len *fh;
|
||
|
|
||
|
- xlog(D_CALL, "MNT1(%s) called", *path);
|
||
|
+ xlog(D_CALL, "Received MNT1(%s) request from %s", *path,
|
||
|
+ host_ntop(sap, buf, sizeof(buf)));
|
||
|
+
|
||
|
fh = get_rootfh(rqstp, path, NULL, &res->fhs_status, 0);
|
||
|
if (fh)
|
||
|
memcpy(&res->fhstatus_u.fhs_fhandle, fh->fh_handle, 32);
|
||
|
@@ -210,23 +217,27 @@ mount_mnt_1_svc(struct svc_req *rqstp, d
|
||
|
}
|
||
|
|
||
|
bool_t
|
||
|
-mount_dump_1_svc(struct svc_req *rqstp, void *argp, mountlist *res)
|
||
|
+mount_dump_1_svc(struct svc_req *rqstp, void *UNUSED(argp), mountlist *res)
|
||
|
{
|
||
|
- struct sockaddr_in *addr = nfs_getrpccaller_in(rqstp->rq_xprt);
|
||
|
+ struct sockaddr *sap = nfs_getrpccaller(rqstp->rq_xprt);
|
||
|
+ char buf[INET6_ADDRSTRLEN];
|
||
|
+
|
||
|
+ xlog(D_CALL, "Received DUMP request from %s",
|
||
|
+ host_ntop(sap, buf, sizeof(buf)));
|
||
|
|
||
|
- xlog(D_CALL, "dump request from %s.", inet_ntoa(addr->sin_addr));
|
||
|
*res = mountlist_list();
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
bool_t
|
||
|
-mount_umnt_1_svc(struct svc_req *rqstp, dirpath *argp, void *resp)
|
||
|
+mount_umnt_1_svc(struct svc_req *rqstp, dirpath *argp, void *UNUSED(resp))
|
||
|
{
|
||
|
- struct sockaddr_in *sin = nfs_getrpccaller_in(rqstp->rq_xprt);
|
||
|
+ struct sockaddr *sap = nfs_getrpccaller(rqstp->rq_xprt);
|
||
|
nfs_export *exp;
|
||
|
char *p = *argp;
|
||
|
char rpath[MAXPATHLEN+1];
|
||
|
+ char buf[INET6_ADDRSTRLEN];
|
||
|
|
||
|
if (*p == '\0')
|
||
|
p = "/";
|
||
|
@@ -236,41 +247,57 @@ mount_umnt_1_svc(struct svc_req *rqstp,
|
||
|
p = rpath;
|
||
|
}
|
||
|
|
||
|
- if (!(exp = auth_authenticate("unmount", sin, p))) {
|
||
|
+ xlog(D_CALL, "Received UMNT(%s) request from %s", p,
|
||
|
+ host_ntop(sap, buf, sizeof(buf)));
|
||
|
+
|
||
|
+ exp = auth_authenticate("unmount", sap, p);
|
||
|
+ if (exp == NULL)
|
||
|
return 1;
|
||
|
- }
|
||
|
|
||
|
- mountlist_del(inet_ntoa(sin->sin_addr), p);
|
||
|
+ mountlist_del(host_ntop(sap, buf, sizeof(buf)), p);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
bool_t
|
||
|
-mount_umntall_1_svc(struct svc_req *rqstp, void *argp, void *resp)
|
||
|
+mount_umntall_1_svc(struct svc_req *rqstp, void *UNUSED(argp),
|
||
|
+ void *UNUSED(resp))
|
||
|
{
|
||
|
+ struct sockaddr *sap = nfs_getrpccaller(rqstp->rq_xprt);
|
||
|
+ char buf[INET6_ADDRSTRLEN];
|
||
|
+
|
||
|
+ xlog(D_CALL, "Received UMNTALL request from %s",
|
||
|
+ host_ntop(sap, buf, sizeof(buf)));
|
||
|
+
|
||
|
/* Reload /etc/xtab if necessary */
|
||
|
auth_reload();
|
||
|
|
||
|
- mountlist_del_all(nfs_getrpccaller_in(rqstp->rq_xprt));
|
||
|
+ mountlist_del_all(nfs_getrpccaller(rqstp->rq_xprt));
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
bool_t
|
||
|
-mount_export_1_svc(struct svc_req *rqstp, void *argp, exports *resp)
|
||
|
+mount_export_1_svc(struct svc_req *rqstp, void *UNUSED(argp), exports *resp)
|
||
|
{
|
||
|
- struct sockaddr_in *addr = nfs_getrpccaller_in(rqstp->rq_xprt);
|
||
|
+ struct sockaddr *sap = nfs_getrpccaller(rqstp->rq_xprt);
|
||
|
+ char buf[INET6_ADDRSTRLEN];
|
||
|
+
|
||
|
+ xlog(D_CALL, "Received EXPORT request from %s.",
|
||
|
+ host_ntop(sap, buf, sizeof(buf)));
|
||
|
|
||
|
- xlog(D_CALL, "export request from %s.", inet_ntoa(addr->sin_addr));
|
||
|
*resp = get_exportlist();
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
bool_t
|
||
|
-mount_exportall_1_svc(struct svc_req *rqstp, void *argp, exports *resp)
|
||
|
+mount_exportall_1_svc(struct svc_req *rqstp, void *UNUSED(argp), exports *resp)
|
||
|
{
|
||
|
- struct sockaddr_in *addr = nfs_getrpccaller_in(rqstp->rq_xprt);
|
||
|
+ struct sockaddr *sap = nfs_getrpccaller(rqstp->rq_xprt);
|
||
|
+ char buf[INET6_ADDRSTRLEN];
|
||
|
+
|
||
|
+ xlog(D_CALL, "Received EXPORTALL request from %s.",
|
||
|
+ host_ntop(sap, buf, sizeof(buf)));
|
||
|
|
||
|
- xlog(D_CALL, "exportall request from %s.", inet_ntoa(addr->sin_addr));
|
||
|
*resp = get_exportlist();
|
||
|
|
||
|
return 1;
|
||
|
@@ -290,11 +317,12 @@ mount_exportall_1_svc(struct svc_req *rq
|
||
|
bool_t
|
||
|
mount_pathconf_2_svc(struct svc_req *rqstp, dirpath *path, ppathcnf *res)
|
||
|
{
|
||
|
- struct sockaddr_in *sin = nfs_getrpccaller_in(rqstp->rq_xprt);
|
||
|
+ struct sockaddr *sap = nfs_getrpccaller(rqstp->rq_xprt);
|
||
|
struct stat stb;
|
||
|
nfs_export *exp;
|
||
|
char rpath[MAXPATHLEN+1];
|
||
|
char *p = *path;
|
||
|
+ char buf[INET6_ADDRSTRLEN];
|
||
|
|
||
|
memset(res, 0, sizeof(*res));
|
||
|
|
||
|
@@ -310,11 +338,14 @@ mount_pathconf_2_svc(struct svc_req *rqs
|
||
|
p = rpath;
|
||
|
}
|
||
|
|
||
|
+ xlog(D_CALL, "Received PATHCONF(%s) request from %s", p,
|
||
|
+ host_ntop(sap, buf, sizeof(buf)));
|
||
|
+
|
||
|
/* Now authenticate the intruder... */
|
||
|
- exp = auth_authenticate("pathconf", sin, p);
|
||
|
- if (!exp) {
|
||
|
+ exp = auth_authenticate("pathconf", sap, p);
|
||
|
+ if (exp == NULL)
|
||
|
return 1;
|
||
|
- } else if (stat(p, &stb) < 0) {
|
||
|
+ else if (stat(p, &stb) < 0) {
|
||
|
xlog(L_WARNING, "can't stat exported dir %s: %s",
|
||
|
p, strerror(errno));
|
||
|
return 1;
|
||
|
@@ -374,11 +405,15 @@ static void set_authflavors(struct mount
|
||
|
bool_t
|
||
|
mount_mnt_3_svc(struct svc_req *rqstp, dirpath *path, mountres3 *res)
|
||
|
{
|
||
|
+ struct sockaddr *sap = nfs_getrpccaller(rqstp->rq_xprt);
|
||
|
struct mountres3_ok *ok = &res->mountres3_u.mountinfo;
|
||
|
+ char buf[INET6_ADDRSTRLEN];
|
||
|
nfs_export *exp;
|
||
|
struct nfs_fh_len *fh;
|
||
|
|
||
|
- xlog(D_CALL, "MNT3(%s) called", *path);
|
||
|
+ xlog(D_CALL, "Received MNT3(%s) request from %s", *path,
|
||
|
+ host_ntop(sap, buf, sizeof(buf)));
|
||
|
+
|
||
|
fh = get_rootfh(rqstp, path, &exp, &res->fhs_status, 1);
|
||
|
if (!fh)
|
||
|
return 1;
|
||
|
@@ -393,12 +428,13 @@ static struct nfs_fh_len *
|
||
|
get_rootfh(struct svc_req *rqstp, dirpath *path, nfs_export **expret,
|
||
|
mountstat3 *error, int v3)
|
||
|
{
|
||
|
- struct sockaddr_in *sin = nfs_getrpccaller_in(rqstp->rq_xprt);
|
||
|
+ struct sockaddr *sap = nfs_getrpccaller(rqstp->rq_xprt);
|
||
|
struct stat stb, estb;
|
||
|
nfs_export *exp;
|
||
|
struct nfs_fh_len *fh;
|
||
|
char rpath[MAXPATHLEN+1];
|
||
|
char *p = *path;
|
||
|
+ char buf[INET6_ADDRSTRLEN];
|
||
|
|
||
|
if (*p == '\0')
|
||
|
p = "/";
|
||
|
@@ -413,8 +449,8 @@ get_rootfh(struct svc_req *rqstp, dirpat
|
||
|
}
|
||
|
|
||
|
/* Now authenticate the intruder... */
|
||
|
- exp = auth_authenticate("mount", sin, p);
|
||
|
- if (!exp) {
|
||
|
+ exp = auth_authenticate("mount", sap, p);
|
||
|
+ if (exp == NULL) {
|
||
|
*error = NFSERR_ACCES;
|
||
|
return NULL;
|
||
|
}
|
||
|
@@ -482,13 +518,13 @@ get_rootfh(struct svc_req *rqstp, dirpat
|
||
|
xtab_append(exp);
|
||
|
|
||
|
if (v3)
|
||
|
- fh = getfh_size ((struct sockaddr *) sin, p, 64);
|
||
|
+ fh = getfh_size((struct sockaddr_in *)sap, p, 64);
|
||
|
if (!v3 || (fh == NULL && errno == EINVAL)) {
|
||
|
/* We first try the new nfs syscall. */
|
||
|
- fh = getfh ((struct sockaddr *) sin, p);
|
||
|
+ fh = getfh((struct sockaddr_in *)sap, p);
|
||
|
if (fh == NULL && errno == EINVAL)
|
||
|
/* Let's try the old one. */
|
||
|
- fh = getfh_old ((struct sockaddr *) sin,
|
||
|
+ fh = getfh_old((struct sockaddr_in *)sap,
|
||
|
stb.st_dev, stb.st_ino);
|
||
|
}
|
||
|
if (fh == NULL && !did_export) {
|
||
|
@@ -503,7 +539,7 @@ get_rootfh(struct svc_req *rqstp, dirpat
|
||
|
}
|
||
|
}
|
||
|
*error = NFS_OK;
|
||
|
- mountlist_add(inet_ntoa(sin->sin_addr), p);
|
||
|
+ mountlist_add(host_ntop(sap, buf, sizeof(buf)), p);
|
||
|
if (expret)
|
||
|
*expret = exp;
|
||
|
return fh;
|
||
|
@@ -536,22 +572,21 @@ static void free_exportlist(exports *eli
|
||
|
|
||
|
static void prune_clients(nfs_export *exp, struct exportnode *e)
|
||
|
{
|
||
|
- struct hostent *hp;
|
||
|
+ struct addrinfo *ai = NULL;
|
||
|
struct groupnode *c, **cp;
|
||
|
|
||
|
cp = &e->ex_groups;
|
||
|
while ((c = *cp) != NULL) {
|
||
|
if (client_gettype(c->gr_name) == MCL_FQDN
|
||
|
- && (hp = gethostbyname(c->gr_name))) {
|
||
|
- hp = hostent_dup(hp);
|
||
|
- if (client_check(exp->m_client, hp)) {
|
||
|
+ && (ai = host_addrinfo(c->gr_name))) {
|
||
|
+ if (client_check(exp->m_client, ai)) {
|
||
|
*cp = c->gr_next;
|
||
|
xfree(c->gr_name);
|
||
|
xfree(c);
|
||
|
- xfree (hp);
|
||
|
+ freeaddrinfo(ai);
|
||
|
continue;
|
||
|
}
|
||
|
- xfree (hp);
|
||
|
+ freeaddrinfo(ai);
|
||
|
}
|
||
|
cp = &(c->gr_next);
|
||
|
}
|
||
|
@@ -712,8 +747,10 @@ main(int argc, char **argv)
|
||
|
usage(argv [0], 1);
|
||
|
}
|
||
|
|
||
|
- /* No more arguments allowed. */
|
||
|
- if (optind != argc || !(nfs_version & 0x7))
|
||
|
+ /* No more arguments allowed.
|
||
|
+ * Require at least one valid version (2, 3, or 4)
|
||
|
+ */
|
||
|
+ if (optind != argc || !(nfs_version & 0xE))
|
||
|
usage(argv [0], 1);
|
||
|
|
||
|
if (chdir(state_dir)) {
|
||
|
@@ -761,12 +798,12 @@ main(int argc, char **argv)
|
||
|
if (new_cache)
|
||
|
cache_open();
|
||
|
|
||
|
- if (nfs_version & 0x1)
|
||
|
+ if (nfs_version & (0x1 << 1)) {
|
||
|
rpc_init("mountd", MOUNTPROG, MOUNTVERS,
|
||
|
mount_dispatch, port);
|
||
|
- if (nfs_version & (0x1 << 1))
|
||
|
rpc_init("mountd", MOUNTPROG, MOUNTVERS_POSIX,
|
||
|
mount_dispatch, port);
|
||
|
+ }
|
||
|
if (nfs_version & (0x1 << 2))
|
||
|
rpc_init("mountd", MOUNTPROG, MOUNTVERS_NFSV3,
|
||
|
mount_dispatch, port);
|
||
|
diff -up nfs-utils-1.2.2/utils/mountd/mountd.h.orig nfs-utils-1.2.2/utils/mountd/mountd.h
|
||
|
--- nfs-utils-1.2.2/utils/mountd/mountd.h.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/utils/mountd/mountd.h 2010-09-16 16:29:35.261220190 -0400
|
||
|
@@ -41,14 +41,19 @@ bool_t mount_mnt_3_svc(struct svc_req *
|
||
|
void mount_dispatch(struct svc_req *, SVCXPRT *);
|
||
|
void auth_init(char *export_file);
|
||
|
unsigned int auth_reload(void);
|
||
|
-nfs_export * auth_authenticate(char *what, struct sockaddr_in *sin,
|
||
|
- char *path);
|
||
|
+nfs_export * auth_authenticate(const char *what,
|
||
|
+ const struct sockaddr *caller,
|
||
|
+ const char *path);
|
||
|
void auth_export(nfs_export *exp);
|
||
|
|
||
|
void mountlist_add(char *host, const char *path);
|
||
|
void mountlist_del(char *host, const char *path);
|
||
|
-void mountlist_del_all(struct sockaddr_in *sin);
|
||
|
+void mountlist_del_all(const struct sockaddr *sap);
|
||
|
mountlist mountlist_list(void);
|
||
|
|
||
|
+void cache_open(void);
|
||
|
+struct nfs_fh_len *
|
||
|
+ cache_get_filehandle(nfs_export *exp, int len, char *p);
|
||
|
+int cache_export(nfs_export *exp, char *path);
|
||
|
|
||
|
#endif /* MOUNTD_H */
|
||
|
diff -up nfs-utils-1.2.2/utils/mountd/rmtab.c.orig nfs-utils-1.2.2/utils/mountd/rmtab.c
|
||
|
--- nfs-utils-1.2.2/utils/mountd/rmtab.c.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/utils/mountd/rmtab.c 2010-09-16 16:29:35.261220190 -0400
|
||
|
@@ -16,7 +16,7 @@
|
||
|
#include <netinet/in.h>
|
||
|
#include <arpa/inet.h>
|
||
|
#include <netdb.h>
|
||
|
-#include "xmalloc.h"
|
||
|
+
|
||
|
#include "misc.h"
|
||
|
#include "exportfs.h"
|
||
|
#include "xio.h"
|
||
|
@@ -131,22 +131,22 @@ mountlist_del(char *hname, const char *p
|
||
|
}
|
||
|
|
||
|
void
|
||
|
-mountlist_del_all(struct sockaddr_in *sin)
|
||
|
+mountlist_del_all(const struct sockaddr *sap)
|
||
|
{
|
||
|
- struct in_addr addr = sin->sin_addr;
|
||
|
- struct hostent *hp;
|
||
|
+ char *hostname;
|
||
|
struct rmtabent *rep;
|
||
|
- nfs_export *exp;
|
||
|
FILE *fp;
|
||
|
int lockid;
|
||
|
|
||
|
if ((lockid = xflock(_PATH_RMTABLCK, "w")) < 0)
|
||
|
return;
|
||
|
- if (!(hp = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET))) {
|
||
|
- xlog(L_ERROR, "can't get hostname of %s", inet_ntoa(addr));
|
||
|
+ hostname = host_canonname(sap);
|
||
|
+ if (hostname == NULL) {
|
||
|
+ char buf[INET6_ADDRSTRLEN];
|
||
|
+ xlog(L_ERROR, "can't get hostname of %s",
|
||
|
+ host_ntop(sap, buf, sizeof(buf)));
|
||
|
goto out_unlock;
|
||
|
}
|
||
|
- hp = hostent_dup (hp);
|
||
|
|
||
|
if (!setrmtabent("r"))
|
||
|
goto out_free;
|
||
|
@@ -155,8 +155,8 @@ mountlist_del_all(struct sockaddr_in *si
|
||
|
goto out_close;
|
||
|
|
||
|
while ((rep = getrmtabent(1, NULL)) != NULL) {
|
||
|
- if (strcmp(rep->r_client, hp->h_name) == 0 &&
|
||
|
- (exp = auth_authenticate("umountall", sin, rep->r_path)))
|
||
|
+ if (strcmp(rep->r_client, hostname) == 0 &&
|
||
|
+ auth_authenticate("umountall", sap, rep->r_path) != NULL)
|
||
|
continue;
|
||
|
fputrmtabent(fp, rep, NULL);
|
||
|
}
|
||
|
@@ -168,11 +168,23 @@ mountlist_del_all(struct sockaddr_in *si
|
||
|
out_close:
|
||
|
endrmtabent(); /* close & unlink */
|
||
|
out_free:
|
||
|
- free (hp);
|
||
|
+ free(hostname);
|
||
|
out_unlock:
|
||
|
xfunlock(lockid);
|
||
|
}
|
||
|
|
||
|
+static void
|
||
|
+mountlist_freeall(mountlist list)
|
||
|
+{
|
||
|
+ while (list != NULL) {
|
||
|
+ mountlist m = list;
|
||
|
+ list = m->ml_next;
|
||
|
+ free(m->ml_hostname);
|
||
|
+ free(m->ml_directory);
|
||
|
+ free(m);
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
mountlist
|
||
|
mountlist_list(void)
|
||
|
{
|
||
|
@@ -182,8 +194,6 @@ mountlist_list(void)
|
||
|
struct rmtabent *rep;
|
||
|
struct stat stb;
|
||
|
int lockid;
|
||
|
- struct in_addr addr;
|
||
|
- struct hostent *he;
|
||
|
|
||
|
if ((lockid = xflock(_PATH_RMTABLCK, "r")) < 0)
|
||
|
return NULL;
|
||
|
@@ -194,26 +204,41 @@ mountlist_list(void)
|
||
|
return NULL;
|
||
|
}
|
||
|
if (stb.st_mtime != last_mtime) {
|
||
|
- while (mlist) {
|
||
|
- mlist = (m = mlist)->ml_next;
|
||
|
- xfree(m->ml_hostname);
|
||
|
- xfree(m->ml_directory);
|
||
|
- xfree(m);
|
||
|
- }
|
||
|
+ mountlist_freeall(mlist);
|
||
|
last_mtime = stb.st_mtime;
|
||
|
|
||
|
setrmtabent("r");
|
||
|
while ((rep = getrmtabent(1, NULL)) != NULL) {
|
||
|
- m = (mountlist) xmalloc(sizeof(*m));
|
||
|
-
|
||
|
- if (reverse_resolve &&
|
||
|
- inet_aton((const char *) rep->r_client, &addr) &&
|
||
|
- (he = gethostbyaddr(&addr, sizeof(addr), AF_INET)))
|
||
|
- m->ml_hostname = xstrdup(he->h_name);
|
||
|
- else
|
||
|
- m->ml_hostname = xstrdup(rep->r_client);
|
||
|
+ m = calloc(1, sizeof(*m));
|
||
|
+ if (m == NULL) {
|
||
|
+ mountlist_freeall(mlist);
|
||
|
+ mlist = NULL;
|
||
|
+ xlog(L_ERROR, "%s: memory allocation failed",
|
||
|
+ __func__);
|
||
|
+ break;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (reverse_resolve) {
|
||
|
+ struct addrinfo *ai;
|
||
|
+ ai = host_pton(rep->r_client);
|
||
|
+ if (ai != NULL) {
|
||
|
+ m->ml_hostname = host_canonname(ai->ai_addr);
|
||
|
+ freeaddrinfo(ai);
|
||
|
+ }
|
||
|
+ }
|
||
|
+ if (m->ml_hostname == NULL)
|
||
|
+ m->ml_hostname = strdup(rep->r_client);
|
||
|
+
|
||
|
+ m->ml_directory = strdup(rep->r_path);
|
||
|
+
|
||
|
+ if (m->ml_hostname == NULL || m->ml_directory == NULL) {
|
||
|
+ mountlist_freeall(mlist);
|
||
|
+ mlist = NULL;
|
||
|
+ xlog(L_ERROR, "%s: memory allocation failed",
|
||
|
+ __func__);
|
||
|
+ break;
|
||
|
+ }
|
||
|
|
||
|
- m->ml_directory = xstrdup(rep->r_path);
|
||
|
m->ml_next = mlist;
|
||
|
mlist = m;
|
||
|
}
|
||
|
diff -up nfs-utils-1.2.2/utils/mount/network.c.orig nfs-utils-1.2.2/utils/mount/network.c
|
||
|
--- nfs-utils-1.2.2/utils/mount/network.c.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/utils/mount/network.c 2010-09-16 16:29:35.252229853 -0400
|
||
|
@@ -53,6 +53,7 @@
|
||
|
#include "parse_opt.h"
|
||
|
#include "network.h"
|
||
|
#include "conffile.h"
|
||
|
+#include "nfslib.h"
|
||
|
|
||
|
#define PMAP_TIMEOUT (10)
|
||
|
#define CONNECT_TIMEOUT (20)
|
||
|
@@ -82,6 +83,7 @@ static const char *nfs_nfs_pgmtbl[] = {
|
||
|
static const char *nfs_transport_opttbl[] = {
|
||
|
"udp",
|
||
|
"tcp",
|
||
|
+ "rdma",
|
||
|
"proto",
|
||
|
NULL,
|
||
|
};
|
||
|
@@ -857,7 +859,14 @@ int nfs_advise_umount(const struct socka
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
- client->cl_auth = authunix_create_default();
|
||
|
+ client->cl_auth = nfs_authsys_create();
|
||
|
+ if (client->cl_auth == NULL) {
|
||
|
+ if (verbose)
|
||
|
+ nfs_error(_("%s: Failed to create RPC auth handle"),
|
||
|
+ progname);
|
||
|
+ CLNT_DESTROY(client);
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
|
||
|
res = CLNT_CALL(client, MOUNTPROC_UMNT,
|
||
|
(xdrproc_t)xdr_dirpath, (caddr_t)argp,
|
||
|
@@ -957,8 +966,10 @@ CLIENT *mnt_openclnt(clnt_addr_t *mnt_se
|
||
|
}
|
||
|
if (clnt) {
|
||
|
/* try to mount hostname:dirname */
|
||
|
- clnt->cl_auth = authunix_create_default();
|
||
|
- return clnt;
|
||
|
+ clnt->cl_auth = nfs_authsys_create();
|
||
|
+ if (clnt->cl_auth)
|
||
|
+ return clnt;
|
||
|
+ CLNT_DESTROY(clnt);
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|
||
|
@@ -1203,6 +1214,8 @@ nfs_nfs_program(struct mount_options *op
|
||
|
return 1;
|
||
|
}
|
||
|
case PO_BAD_VALUE:
|
||
|
+ nfs_error(_("%s: invalid value for 'nfsprog=' option"),
|
||
|
+ progname);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
@@ -1242,9 +1255,12 @@ nfs_nfs_version(struct mount_options *op
|
||
|
}
|
||
|
return 0;
|
||
|
case PO_NOT_FOUND:
|
||
|
- nfs_error(_("%s: option parsing error\n"),
|
||
|
+ nfs_error(_("%s: parsing error on 'vers=' option\n"),
|
||
|
progname);
|
||
|
+ return 0;
|
||
|
case PO_BAD_VALUE:
|
||
|
+ nfs_error(_("%s: invalid value for 'vers=' option"),
|
||
|
+ progname);
|
||
|
return 0;
|
||
|
}
|
||
|
case 4: /* nfsvers */
|
||
|
@@ -1256,9 +1272,12 @@ nfs_nfs_version(struct mount_options *op
|
||
|
}
|
||
|
return 0;
|
||
|
case PO_NOT_FOUND:
|
||
|
- nfs_error(_("%s: option parsing error\n"),
|
||
|
+ nfs_error(_("%s: parsing error on 'nfsvers=' option\n"),
|
||
|
progname);
|
||
|
+ return 0;
|
||
|
case PO_BAD_VALUE:
|
||
|
+ nfs_error(_("%s: invalid value for 'nfsvers=' option"),
|
||
|
+ progname);
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
@@ -1289,11 +1308,16 @@ nfs_nfs_protocol(struct mount_options *o
|
||
|
case 1: /* tcp */
|
||
|
*protocol = IPPROTO_TCP;
|
||
|
return 1;
|
||
|
- case 2: /* proto */
|
||
|
+ case 2: /* rdma */
|
||
|
+ *protocol = NFSPROTO_RDMA;
|
||
|
+ return 1;
|
||
|
+ case 3: /* proto */
|
||
|
option = po_get(options, "proto");
|
||
|
if (option != NULL) {
|
||
|
if (!nfs_get_proto(option, &family, protocol)) {
|
||
|
errno = EPROTONOSUPPORT;
|
||
|
+ nfs_error(_("%s: Failed to find '%s' protocol"),
|
||
|
+ progname, option);
|
||
|
return 0;
|
||
|
}
|
||
|
return 1;
|
||
|
@@ -1327,6 +1351,8 @@ nfs_nfs_port(struct mount_options *optio
|
||
|
return 1;
|
||
|
}
|
||
|
case PO_BAD_VALUE:
|
||
|
+ nfs_error(_("%s: invalid value for 'port=' option"),
|
||
|
+ progname);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
@@ -1342,7 +1368,7 @@ nfs_nfs_port(struct mount_options *optio
|
||
|
sa_family_t config_default_family = AF_UNSPEC;
|
||
|
|
||
|
static int
|
||
|
-nfs_verify_family(sa_family_t family)
|
||
|
+nfs_verify_family(sa_family_t UNUSED(family))
|
||
|
{
|
||
|
return 1;
|
||
|
}
|
||
|
@@ -1374,14 +1400,20 @@ int nfs_nfs_proto_family(struct mount_op
|
||
|
switch (po_rightmost(options, nfs_transport_opttbl)) {
|
||
|
case 0: /* udp */
|
||
|
case 1: /* tcp */
|
||
|
+ case 2: /* rdma */
|
||
|
/* for compatibility; these are always AF_INET */
|
||
|
*family = AF_INET;
|
||
|
return 1;
|
||
|
- case 2: /* proto */
|
||
|
+ case 3: /* proto */
|
||
|
option = po_get(options, "proto");
|
||
|
if (option != NULL &&
|
||
|
- !nfs_get_proto(option, &tmp_family, &protocol))
|
||
|
- goto out_err;
|
||
|
+ !nfs_get_proto(option, &tmp_family, &protocol)) {
|
||
|
+
|
||
|
+ nfs_error(_("%s: Failed to find '%s' protocol"),
|
||
|
+ progname, option);
|
||
|
+ errno = EPROTONOSUPPORT;
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
}
|
||
|
|
||
|
if (!nfs_verify_family(tmp_family))
|
||
|
@@ -1414,6 +1446,8 @@ nfs_mount_program(struct mount_options *
|
||
|
return 1;
|
||
|
}
|
||
|
case PO_BAD_VALUE:
|
||
|
+ nfs_error(_("%s: invalid value for 'mountprog=' option"),
|
||
|
+ progname);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
@@ -1443,6 +1477,8 @@ nfs_mount_version(struct mount_options *
|
||
|
return 1;
|
||
|
}
|
||
|
case PO_BAD_VALUE:
|
||
|
+ nfs_error(_("%s: invalid value for 'mountvers=' option"),
|
||
|
+ progname);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
@@ -1469,6 +1505,8 @@ nfs_mount_protocol(struct mount_options
|
||
|
if (option != NULL) {
|
||
|
if (!nfs_get_proto(option, &family, protocol)) {
|
||
|
errno = EPROTONOSUPPORT;
|
||
|
+ nfs_error(_("%s: Failed to find '%s' protocol"),
|
||
|
+ progname, option);
|
||
|
return 0;
|
||
|
}
|
||
|
return 1;
|
||
|
@@ -1501,6 +1539,8 @@ nfs_mount_port(struct mount_options *opt
|
||
|
return 1;
|
||
|
}
|
||
|
case PO_BAD_VALUE:
|
||
|
+ nfs_error(_("%s: invalid value for 'mountport=' option"),
|
||
|
+ progname);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
@@ -1526,8 +1566,12 @@ int nfs_mount_proto_family(struct mount_
|
||
|
|
||
|
option = po_get(options, "mountproto");
|
||
|
if (option != NULL) {
|
||
|
- if (!nfs_get_proto(option, &tmp_family, &protocol))
|
||
|
+ if (!nfs_get_proto(option, &tmp_family, &protocol)) {
|
||
|
+ nfs_error(_("%s: Failed to find '%s' protocol"),
|
||
|
+ progname, option);
|
||
|
+ errno = EPROTONOSUPPORT;
|
||
|
goto out_err;
|
||
|
+ }
|
||
|
if (!nfs_verify_family(tmp_family))
|
||
|
goto out_err;
|
||
|
*family = tmp_family;
|
||
|
diff -up nfs-utils-1.2.2/utils/mount/nfs4mount.c.orig nfs-utils-1.2.2/utils/mount/nfs4mount.c
|
||
|
--- nfs-utils-1.2.2/utils/mount/nfs4mount.c.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/utils/mount/nfs4mount.c 2010-09-16 16:29:35.254210443 -0400
|
||
|
@@ -146,7 +146,7 @@ static int fill_ipv4_sockaddr(const char
|
||
|
progname, hostname);
|
||
|
return -1;
|
||
|
}
|
||
|
- if (hp->h_length > sizeof(struct in_addr)) {
|
||
|
+ if (hp->h_length > (int)sizeof(struct in_addr)) {
|
||
|
nfs_error(_("%s: got bad hp->h_length"), progname);
|
||
|
hp->h_length = sizeof(struct in_addr);
|
||
|
}
|
||
|
diff -up nfs-utils-1.2.2/utils/mount/nfs.man.orig nfs-utils-1.2.2/utils/mount/nfs.man
|
||
|
--- nfs-utils-1.2.2/utils/mount/nfs.man.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/utils/mount/nfs.man 2010-09-16 16:29:35.253220019 -0400
|
||
|
@@ -3,8 +3,6 @@
|
||
|
.SH NAME
|
||
|
nfs \- fstab format and options for the
|
||
|
.B nfs
|
||
|
-and
|
||
|
-.B nfs4
|
||
|
file systems
|
||
|
.SH SYNOPSIS
|
||
|
.I /etc/fstab
|
||
|
@@ -71,14 +69,10 @@ for details on specifying raw IPv6 addre
|
||
|
.P
|
||
|
The
|
||
|
.I fstype
|
||
|
-field contains either "nfs" (for version 2 or version 3 NFS mounts)
|
||
|
-or "nfs4" (for NFS version 4 mounts).
|
||
|
+field contains "nfs", for whatever version of the protocol.
|
||
|
The
|
||
|
.B nfs
|
||
|
-and
|
||
|
-.B nfs4
|
||
|
-file system types share similar mount options,
|
||
|
-which are described below.
|
||
|
+allow several mount options, which are described below.
|
||
|
.SH "MOUNT OPTIONS"
|
||
|
Refer to
|
||
|
.BR mount (8)
|
||
|
@@ -89,14 +83,8 @@ specify any mount options, use the gener
|
||
|
in
|
||
|
.IR /etc/fstab .
|
||
|
.DT
|
||
|
-.SS "Valid options for either the nfs or nfs4 file system type"
|
||
|
-These options are valid to use when mounting either
|
||
|
-.B nfs
|
||
|
-or
|
||
|
-.B nfs4
|
||
|
-file system types.
|
||
|
-They imply the same behavior
|
||
|
-and have the same default for both file system types.
|
||
|
+.SS "Options supported by all versions"
|
||
|
+These options are valid to use with any NFS version.
|
||
|
.TP 1.5i
|
||
|
.BR soft " / " hard
|
||
|
Determines the recovery behavior of the NFS client
|
||
|
@@ -476,11 +464,9 @@ by other clients, but can impact applica
|
||
|
.IP
|
||
|
The DATA AND METADATA COHERENCE section contains a
|
||
|
detailed discussion of these trade-offs.
|
||
|
-.SS "Valid options for the nfs file system type"
|
||
|
+.SS "Options for versions 2 and 3 only"
|
||
|
Use these options, along with the options in the above subsection,
|
||
|
-for mounting the
|
||
|
-.B nfs
|
||
|
-file system type.
|
||
|
+for NFSv2/v3 only. They will be ignored for newer versions.
|
||
|
.TP 1.5i
|
||
|
.BI proto= netid
|
||
|
The transport protocol name and protocol family the NFS client uses
|
||
|
@@ -495,7 +481,10 @@ command,
|
||
|
.I netid
|
||
|
is a valid netid listed in
|
||
|
.IR /etc/netconfig .
|
||
|
-Otherwise,
|
||
|
+The value "rdma" may also be specified.
|
||
|
+If the
|
||
|
+.B mount.nfs
|
||
|
+command does not have TI-RPC support, then
|
||
|
.I netid
|
||
|
is one of "tcp," "udp," or "rdma," and only IPv4 may be used.
|
||
|
.IP
|
||
|
@@ -537,6 +526,12 @@ option is an alternative to specifying
|
||
|
.BR proto=tcp.
|
||
|
It is included for compatibility with other operating systems.
|
||
|
.TP 1.5i
|
||
|
+.B rdma
|
||
|
+The
|
||
|
+.B rdma
|
||
|
+option is an alternative to specifying
|
||
|
+.BR proto=rdma.
|
||
|
+.TP 1.5i
|
||
|
.BI port= n
|
||
|
The numeric value of the server's NFS service port.
|
||
|
If the server's NFS service is not available on the specified port,
|
||
|
@@ -623,14 +618,9 @@ in such cases.
|
||
|
.TP 1.5i
|
||
|
.BI nfsvers= n
|
||
|
The NFS protocol version number used to contact the server's NFS service.
|
||
|
-The Linux client supports version 2 and version 3 of the NFS protocol
|
||
|
-when using the file system type
|
||
|
-.BR nfs .
|
||
|
-If the server does not support the requested version,
|
||
|
-the mount request fails.
|
||
|
-If this option is not specified, the client attempts to use version 3,
|
||
|
-but negotiates the NFS version with the server if version 3 support
|
||
|
-is not available.
|
||
|
+If the server does not support the requested version, the mount request fails.
|
||
|
+If this option is not specified, the client negociate a suitable version with
|
||
|
+the server, trying version 4 first, version 3 second, and version 2 last.
|
||
|
.TP 1.5i
|
||
|
.BI vers= n
|
||
|
This option is an alternative to the
|
||
|
@@ -727,11 +717,9 @@ If this option is not specified, the NFS
|
||
|
on NFS version 3 mounts to read small directories.
|
||
|
Some applications perform better if the client uses only READDIR requests
|
||
|
for all directories.
|
||
|
-.SS "Valid options for the nfs4 file system type"
|
||
|
+.SS "Options for version 4 only"
|
||
|
Use these options, along with the options in the first subsection above,
|
||
|
-for mounting the
|
||
|
-.B nfs4
|
||
|
-file system type.
|
||
|
+for NFSv4 only. They will be ignored with older versions.
|
||
|
.TP 1.5i
|
||
|
.BI proto= netid
|
||
|
The transport protocol name and protocol family the NFS client uses
|
||
|
@@ -828,6 +816,13 @@ In the presence of multiple client netwo
|
||
|
special routing policies,
|
||
|
or atypical network topologies,
|
||
|
the exact address to use for callbacks may be nontrivial to determine.
|
||
|
+.SH nfs4 FILE SYSTEM TYPE
|
||
|
+The
|
||
|
+.BR nfs4
|
||
|
+file system type is an old syntax for specifying NFSv4 usage. It can still
|
||
|
+be used with all NFSv4-specific and common options, excepted the
|
||
|
+.B nfsvers
|
||
|
+mount option.
|
||
|
.SH MOUNT CONFIGURATION FILE
|
||
|
If the mount command is configured to do so, all of the mount options
|
||
|
described in the previous section can also be configured in the
|
||
|
@@ -849,12 +844,11 @@ file system type and specify the
|
||
|
.B nfsvers=3
|
||
|
mount option.
|
||
|
To mount using NFS version 4,
|
||
|
-use the
|
||
|
-.B nfs4
|
||
|
-file system type.
|
||
|
-The
|
||
|
-.B nfsvers
|
||
|
-mount option is not supported for the
|
||
|
+use either the
|
||
|
+.B nfs
|
||
|
+file system type, with the
|
||
|
+.B nfsvers=4
|
||
|
+mount option, or the
|
||
|
.B nfs4
|
||
|
file system type.
|
||
|
.P
|
||
|
diff -up nfs-utils-1.2.2/utils/mount/nfsmount.c.orig nfs-utils-1.2.2/utils/mount/nfsmount.c
|
||
|
--- nfs-utils-1.2.2/utils/mount/nfsmount.c.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/utils/mount/nfsmount.c 2010-09-16 16:29:35.255249968 -0400
|
||
|
@@ -510,8 +510,12 @@ nfsmount(const char *spec, const char *n
|
||
|
int val;
|
||
|
static int doonce = 0;
|
||
|
|
||
|
- clnt_addr_t mnt_server = { &mounthost, };
|
||
|
- clnt_addr_t nfs_server = { &hostname, };
|
||
|
+ clnt_addr_t mnt_server = {
|
||
|
+ .hostname = &mounthost
|
||
|
+ };
|
||
|
+ clnt_addr_t nfs_server = {
|
||
|
+ .hostname = &hostname
|
||
|
+ };
|
||
|
struct sockaddr_in *nfs_saddr = &nfs_server.saddr;
|
||
|
struct pmap *mnt_pmap = &mnt_server.pmap,
|
||
|
*nfs_pmap = &nfs_server.pmap;
|
||
|
diff -up nfs-utils-1.2.2/utils/mount/nfsumount.c.orig nfs-utils-1.2.2/utils/mount/nfsumount.c
|
||
|
--- nfs-utils-1.2.2/utils/mount/nfsumount.c.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/utils/mount/nfsumount.c 2010-09-16 16:29:35.255249968 -0400
|
||
|
@@ -179,10 +179,8 @@ static int nfs_umount_do_umnt(struct mou
|
||
|
struct pmap nfs_pmap, mnt_pmap;
|
||
|
sa_family_t family;
|
||
|
|
||
|
- if (!nfs_options2pmap(options, &nfs_pmap, &mnt_pmap)) {
|
||
|
- nfs_error(_("%s: bad mount options"), progname);
|
||
|
+ if (!nfs_options2pmap(options, &nfs_pmap, &mnt_pmap))
|
||
|
return EX_FAIL;
|
||
|
- }
|
||
|
|
||
|
/* Skip UMNT call for vers=4 mounts */
|
||
|
if (nfs_pmap.pm_vers == 4)
|
||
|
diff -up nfs-utils-1.2.2/utils/mount/stropts.c.orig nfs-utils-1.2.2/utils/mount/stropts.c
|
||
|
--- nfs-utils-1.2.2/utils/mount/stropts.c.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/utils/mount/stropts.c 2010-09-16 16:29:35.256219797 -0400
|
||
|
@@ -302,11 +302,16 @@ static int nfs_set_version(struct nfsmou
|
||
|
|
||
|
if (strncmp(mi->type, "nfs4", 4) == 0)
|
||
|
mi->version = 4;
|
||
|
- else {
|
||
|
- char *option = po_get(mi->options, "proto");
|
||
|
- if (option && strcmp(option, "rdma") == 0)
|
||
|
- mi->version = 3;
|
||
|
- }
|
||
|
+
|
||
|
+ /*
|
||
|
+ * Before 2.6.32, the kernel NFS client didn't
|
||
|
+ * support "-t nfs vers=4" mounts, so NFS version
|
||
|
+ * 4 cannot be included when autonegotiating
|
||
|
+ * while running on those kernels.
|
||
|
+ */
|
||
|
+ if (mi->version == 0 &&
|
||
|
+ linux_version_code() <= MAKE_VERSION(2, 6, 31))
|
||
|
+ mi->version = 3;
|
||
|
|
||
|
/*
|
||
|
* If we still don't know, check for version-specific
|
||
|
@@ -490,14 +495,18 @@ nfs_rewrite_pmap_mount_options(struct mo
|
||
|
union nfs_sockaddr mnt_address;
|
||
|
struct sockaddr *mnt_saddr = &mnt_address.sa;
|
||
|
socklen_t mnt_salen = sizeof(mnt_address);
|
||
|
+ unsigned long protocol;
|
||
|
struct pmap mnt_pmap;
|
||
|
- char *option;
|
||
|
|
||
|
/*
|
||
|
- * Skip option negotiation for proto=rdma mounts.
|
||
|
+ * Version and transport negotiation is not required
|
||
|
+ * and does not work for RDMA mounts.
|
||
|
*/
|
||
|
- option = po_get(options, "proto");
|
||
|
- if (option && strcmp(option, "rdma") == 0)
|
||
|
+ if (!nfs_nfs_protocol(options, &protocol)) {
|
||
|
+ errno = EINVAL;
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+ if (protocol == NFSPROTO_RDMA)
|
||
|
goto out;
|
||
|
|
||
|
/*
|
||
|
@@ -538,7 +547,10 @@ nfs_rewrite_pmap_mount_options(struct mo
|
||
|
|
||
|
if (!nfs_construct_new_options(options, nfs_saddr, &nfs_pmap,
|
||
|
mnt_saddr, &mnt_pmap)) {
|
||
|
- errno = EINVAL;
|
||
|
+ if (rpc_createerr.cf_stat == RPC_UNKNOWNPROTO)
|
||
|
+ errno = EPROTONOSUPPORT;
|
||
|
+ else
|
||
|
+ errno = EINVAL;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
@@ -586,18 +598,21 @@ static int nfs_do_mount_v3v2(struct nfsm
|
||
|
errno = ENOMEM;
|
||
|
return result;
|
||
|
}
|
||
|
-
|
||
|
+ errno = 0;
|
||
|
if (!nfs_append_addr_option(sap, salen, options)) {
|
||
|
- errno = EINVAL;
|
||
|
+ if (errno == 0)
|
||
|
+ errno = EINVAL;
|
||
|
goto out_fail;
|
||
|
}
|
||
|
|
||
|
if (!nfs_fix_mounthost_option(options, mi->hostname)) {
|
||
|
- errno = EINVAL;
|
||
|
+ if (errno == 0)
|
||
|
+ errno = EINVAL;
|
||
|
goto out_fail;
|
||
|
}
|
||
|
if (!mi->fake && !nfs_verify_lock_option(options)) {
|
||
|
- errno = EINVAL;
|
||
|
+ if (errno == 0)
|
||
|
+ errno = EINVAL;
|
||
|
goto out_fail;
|
||
|
}
|
||
|
|
||
|
@@ -741,6 +756,47 @@ static int nfs_try_mount_v4(struct nfsmo
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
+ * Handle NFS version and transport protocol
|
||
|
+ * autonegotiation.
|
||
|
+ *
|
||
|
+ * When no version or protocol is specified on the
|
||
|
+ * command line, mount.nfs negotiates with the server
|
||
|
+ * to determine appropriate settings for the new
|
||
|
+ * mount point.
|
||
|
+ *
|
||
|
+ * Returns TRUE if successful, otherwise FALSE.
|
||
|
+ * "errno" is set to reflect the individual error.
|
||
|
+ */
|
||
|
+static int nfs_autonegotiate(struct nfsmount_info *mi)
|
||
|
+{
|
||
|
+ int result;
|
||
|
+
|
||
|
+ result = nfs_try_mount_v4(mi);
|
||
|
+ if (result)
|
||
|
+ return result;
|
||
|
+
|
||
|
+ switch (errno) {
|
||
|
+ case EPROTONOSUPPORT:
|
||
|
+ /* A clear indication that the server or our
|
||
|
+ * client does not support NFS version 4. */
|
||
|
+ goto fall_back;
|
||
|
+ case ENOENT:
|
||
|
+ /* Legacy Linux servers don't export an NFS
|
||
|
+ * version 4 pseudoroot. */
|
||
|
+ goto fall_back;
|
||
|
+ case EPERM:
|
||
|
+ /* Linux servers prior to 2.6.25 may return
|
||
|
+ * EPERM when NFS version 4 is not supported. */
|
||
|
+ goto fall_back;
|
||
|
+ default:
|
||
|
+ return result;
|
||
|
+ }
|
||
|
+
|
||
|
+fall_back:
|
||
|
+ return nfs_try_mount_v3v2(mi);
|
||
|
+}
|
||
|
+
|
||
|
+/*
|
||
|
* This is a single pass through the fg/bg loop.
|
||
|
*
|
||
|
* Returns TRUE if successful, otherwise FALSE.
|
||
|
@@ -752,20 +808,8 @@ static int nfs_try_mount(struct nfsmount
|
||
|
|
||
|
switch (mi->version) {
|
||
|
case 0:
|
||
|
- if (linux_version_code() > MAKE_VERSION(2, 6, 31)) {
|
||
|
- errno = 0;
|
||
|
- result = nfs_try_mount_v4(mi);
|
||
|
- if (errno != EPROTONOSUPPORT) {
|
||
|
- /*
|
||
|
- * To deal with legacy Linux servers that don't
|
||
|
- * automatically export a pseudo root, retry
|
||
|
- * ENOENT errors using version 3. And for
|
||
|
- * Linux servers prior to 2.6.25, retry EPERM
|
||
|
- */
|
||
|
- if (errno != ENOENT && errno != EPERM)
|
||
|
- break;
|
||
|
- }
|
||
|
- }
|
||
|
+ result = nfs_autonegotiate(mi);
|
||
|
+ break;
|
||
|
case 2:
|
||
|
case 3:
|
||
|
result = nfs_try_mount_v3v2(mi);
|
||
|
@@ -799,6 +843,7 @@ static int nfs_is_permanent_error(int er
|
||
|
case ESTALE:
|
||
|
case ETIMEDOUT:
|
||
|
case ECONNREFUSED:
|
||
|
+ case EHOSTUNREACH:
|
||
|
return 0; /* temporary */
|
||
|
default:
|
||
|
return 1; /* permanent */
|
||
|
@@ -922,6 +967,26 @@ static int nfsmount_bg(struct nfsmount_i
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
+ * Usually all that is needed for an NFS remount is to change
|
||
|
+ * generic mount options like "sync" or "ro". These generic
|
||
|
+ * options are controlled by mi->flags, not by text-based
|
||
|
+ * options, and no contact with the server is needed.
|
||
|
+ *
|
||
|
+ * Take care with the /etc/mtab entry for this mount; just
|
||
|
+ * calling update_mtab() will change an "-t nfs -o vers=4"
|
||
|
+ * mount to an "-t nfs -o remount" mount, and that will
|
||
|
+ * confuse umount.nfs.
|
||
|
+ *
|
||
|
+ * Returns a valid mount command exit code.
|
||
|
+ */
|
||
|
+static int nfs_remount(struct nfsmount_info *mi)
|
||
|
+{
|
||
|
+ if (nfs_sys_mount(mi, mi->options))
|
||
|
+ return EX_SUCCESS;
|
||
|
+ return EX_FAIL;
|
||
|
+}
|
||
|
+
|
||
|
+/*
|
||
|
* Process mount options and try a mount system call.
|
||
|
*
|
||
|
* Returns a valid mount command exit code.
|
||
|
@@ -937,6 +1002,12 @@ static int nfsmount_start(struct nfsmoun
|
||
|
if (!nfs_validate_options(mi))
|
||
|
return EX_FAIL;
|
||
|
|
||
|
+ /*
|
||
|
+ * Avoid retry and negotiation logic when remounting
|
||
|
+ */
|
||
|
+ if (mi->flags & MS_REMOUNT)
|
||
|
+ return nfs_remount(mi);
|
||
|
+
|
||
|
if (po_rightmost(mi->options, nfs_background_opttbl) == 0)
|
||
|
return nfsmount_bg(mi);
|
||
|
else
|
||
|
@@ -953,6 +1024,8 @@ static int nfsmount_start(struct nfsmoun
|
||
|
* (input and output argument)
|
||
|
* @fake: flag indicating whether to carry out the whole operation
|
||
|
* @child: one if this is a mount daemon (bg)
|
||
|
+ *
|
||
|
+ * Returns a valid mount command exit code.
|
||
|
*/
|
||
|
int nfsmount_string(const char *spec, const char *node, const char *type,
|
||
|
int flags, char **extra_opts, int fake, int child)
|
||
|
diff -up nfs-utils-1.2.2/utils/nfsd/nfsd.c.orig nfs-utils-1.2.2/utils/nfsd/nfsd.c
|
||
|
--- nfs-utils-1.2.2/utils/nfsd/nfsd.c.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/utils/nfsd/nfsd.c 2010-09-16 16:29:35.262240028 -0400
|
||
|
@@ -246,6 +246,9 @@ main(int argc, char **argv)
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
+ /* make sure nfsdfs is mounted if it's available */
|
||
|
+ nfssvc_mount_nfsdfs(progname);
|
||
|
+
|
||
|
/* can only change number of threads if nfsd is already up */
|
||
|
if (nfssvc_inuse()) {
|
||
|
socket_up = 1;
|
||
|
diff -up nfs-utils-1.2.2/utils/nfsd/nfssvc.c.orig nfs-utils-1.2.2/utils/nfsd/nfssvc.c
|
||
|
--- nfs-utils-1.2.2/utils/nfsd/nfssvc.c.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/utils/nfsd/nfssvc.c 2010-09-16 16:29:35.263239998 -0400
|
||
|
@@ -15,9 +15,11 @@
|
||
|
#include <netdb.h>
|
||
|
#include <netinet/in.h>
|
||
|
#include <arpa/inet.h>
|
||
|
+#include <sys/stat.h>
|
||
|
#include <unistd.h>
|
||
|
#include <fcntl.h>
|
||
|
#include <errno.h>
|
||
|
+#include <stdlib.h>
|
||
|
|
||
|
#include "nfslib.h"
|
||
|
#include "xlog.h"
|
||
|
@@ -31,9 +33,13 @@
|
||
|
*/
|
||
|
#undef IPV6_SUPPORTED
|
||
|
|
||
|
-#define NFSD_PORTS_FILE "/proc/fs/nfsd/portlist"
|
||
|
-#define NFSD_VERS_FILE "/proc/fs/nfsd/versions"
|
||
|
-#define NFSD_THREAD_FILE "/proc/fs/nfsd/threads"
|
||
|
+#ifndef NFSD_FS_DIR
|
||
|
+#define NFSD_FS_DIR "/proc/fs/nfsd"
|
||
|
+#endif
|
||
|
+
|
||
|
+#define NFSD_PORTS_FILE NFSD_FS_DIR "/portlist"
|
||
|
+#define NFSD_VERS_FILE NFSD_FS_DIR "/versions"
|
||
|
+#define NFSD_THREAD_FILE NFSD_FS_DIR "/threads"
|
||
|
|
||
|
/*
|
||
|
* declaring a common static scratch buffer here keeps us from having to
|
||
|
@@ -44,6 +50,46 @@
|
||
|
char buf[128];
|
||
|
|
||
|
/*
|
||
|
+ * Using the "new" interfaces for nfsd requires that /proc/fs/nfsd is
|
||
|
+ * actually mounted. Make an attempt to mount it here if it doesn't appear
|
||
|
+ * to be. If the mount attempt fails, no big deal -- fall back to using nfsctl
|
||
|
+ * instead.
|
||
|
+ */
|
||
|
+void
|
||
|
+nfssvc_mount_nfsdfs(char *progname)
|
||
|
+{
|
||
|
+ int err;
|
||
|
+ struct stat statbuf;
|
||
|
+
|
||
|
+ err = stat(NFSD_THREAD_FILE, &statbuf);
|
||
|
+ if (err == 0)
|
||
|
+ return;
|
||
|
+
|
||
|
+ if (errno != ENOENT) {
|
||
|
+ xlog(L_ERROR, "Unable to stat %s: errno %d (%m)",
|
||
|
+ NFSD_THREAD_FILE, errno);
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
+ /*
|
||
|
+ * this call can return an error if modprobe is set up to automatically
|
||
|
+ * mount nfsdfs when nfsd.ko is plugged in. So, ignore the return
|
||
|
+ * code from it and just check for the "threads" file afterward.
|
||
|
+ */
|
||
|
+ system("/bin/mount -t nfsd nfsd " NFSD_FS_DIR " >/dev/null 2>&1");
|
||
|
+
|
||
|
+ err = stat(NFSD_THREAD_FILE, &statbuf);
|
||
|
+ if (err == 0)
|
||
|
+ return;
|
||
|
+
|
||
|
+ xlog(L_WARNING, "Unable to access " NFSD_FS_DIR " errno %d (%m)."
|
||
|
+ "\nPlease try, as root, 'mount -t nfsd nfsd " NFSD_FS_DIR
|
||
|
+ "' and then restart %s to correct the problem", errno, progname);
|
||
|
+
|
||
|
+ return;
|
||
|
+}
|
||
|
+
|
||
|
+/*
|
||
|
* Are there already sockets configured? If not, then it is safe to try to
|
||
|
* open some and pass them through.
|
||
|
*
|
||
|
@@ -181,7 +227,7 @@ nfssvc_setfds(const struct addrinfo *hin
|
||
|
}
|
||
|
|
||
|
snprintf(buf, sizeof(buf), "%d\n", sockfd);
|
||
|
- if (write(fd, buf, strlen(buf)) != strlen(buf)) {
|
||
|
+ if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf)) {
|
||
|
/*
|
||
|
* this error may be common on older kernels that don't
|
||
|
* support IPv6, so turn into a debug message.
|
||
|
@@ -251,7 +297,7 @@ nfssvc_setvers(unsigned int ctlbits, int
|
||
|
}
|
||
|
xlog(D_GENERAL, "Writing version string to kernel: %s", buf);
|
||
|
snprintf(ptr+off, sizeof(buf) - off, "\n");
|
||
|
- if (write(fd, buf, strlen(buf)) != strlen(buf))
|
||
|
+ if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf))
|
||
|
xlog(L_ERROR, "Setting version failed: errno %d (%m)", errno);
|
||
|
|
||
|
close(fd);
|
||
|
@@ -277,7 +323,7 @@ nfssvc_threads(unsigned short port, cons
|
||
|
snprintf(buf, sizeof(buf), "%d\n", nrservs);
|
||
|
n = write(fd, buf, strlen(buf));
|
||
|
close(fd);
|
||
|
- if (n != strlen(buf))
|
||
|
+ if (n != (ssize_t)strlen(buf))
|
||
|
return -1;
|
||
|
else
|
||
|
return 0;
|
||
|
diff -up nfs-utils-1.2.2/utils/nfsd/nfssvc.h.orig nfs-utils-1.2.2/utils/nfsd/nfssvc.h
|
||
|
--- nfs-utils-1.2.2/utils/nfsd/nfssvc.h.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/utils/nfsd/nfssvc.h 2010-09-16 16:29:35.263239998 -0400
|
||
|
@@ -20,6 +20,7 @@
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
+void nfssvc_mount_nfsdfs(char *progname);
|
||
|
int nfssvc_inuse(void);
|
||
|
int nfssvc_set_sockets(const int family, const unsigned int protobits,
|
||
|
const char *host, const char *port);
|
||
|
diff -up nfs-utils-1.2.2/utils/nfsstat/nfsstat.c.orig nfs-utils-1.2.2/utils/nfsstat/nfsstat.c
|
||
|
--- nfs-utils-1.2.2/utils/nfsstat/nfsstat.c.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/utils/nfsstat/nfsstat.c 2010-09-16 16:29:35.264239903 -0400
|
||
|
@@ -31,7 +31,7 @@ enum {
|
||
|
SRVPROC3_SZ = 22,
|
||
|
CLTPROC3_SZ = 22,
|
||
|
SRVPROC4_SZ = 2,
|
||
|
- CLTPROC4_SZ = 48,
|
||
|
+ CLTPROC4_SZ = 49,
|
||
|
SRVPROC4OPS_SZ = 59,
|
||
|
};
|
||
|
|
||
|
@@ -118,6 +118,7 @@ static const char * nfscltproc4name[CLTP
|
||
|
"remove", "rename", "link", "symlink", "create", "pathconf",
|
||
|
"statfs", "readlink", "readdir", "server_caps", "delegreturn", "getacl",
|
||
|
"setacl", "fs_locations",
|
||
|
+ "rel_lkowner",
|
||
|
/* nfsv4.1 client ops */
|
||
|
"exchange_id",
|
||
|
"create_ses",
|
||
|
@@ -791,7 +792,7 @@ print_callstats(const char *hdr, const c
|
||
|
{
|
||
|
unsigned long long total;
|
||
|
unsigned long long pct;
|
||
|
- int i, j;
|
||
|
+ unsigned int i, j;
|
||
|
|
||
|
fputs(hdr, stdout);
|
||
|
for (i = 0, total = 0; i < nr; i++)
|
||
|
@@ -816,7 +817,7 @@ print_callstats_list(const char *hdr, co
|
||
|
unsigned int *callinfo, unsigned int nr)
|
||
|
{
|
||
|
unsigned long long calltotal;
|
||
|
- int i;
|
||
|
+ unsigned int i;
|
||
|
|
||
|
for (i = 0, calltotal = 0; i < nr; i++) {
|
||
|
calltotal += callinfo[i];
|
||
|
@@ -1118,7 +1119,7 @@ unpause(int sig)
|
||
|
time_diff = difftime(endtime, starttime);
|
||
|
minutes = time_diff / 60;
|
||
|
seconds = (int)time_diff % 60;
|
||
|
- printf("Signal received; displaying (only) statistics gathered over the last %d minutes, %d seconds:\n\n", minutes, seconds);
|
||
|
+ printf("Signal %d received; displaying (only) statistics gathered over the last %d minutes, %d seconds:\n\n", sig, minutes, seconds);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
diff -up nfs-utils-1.2.2/utils/showmount/showmount.c.orig nfs-utils-1.2.2/utils/showmount/showmount.c
|
||
|
--- nfs-utils-1.2.2/utils/showmount/showmount.c.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/utils/showmount/showmount.c 2010-09-16 16:29:35.264239903 -0400
|
||
|
@@ -194,7 +194,13 @@ int main(int argc, char **argv)
|
||
|
}
|
||
|
|
||
|
mclient = nfs_get_mount_client(hostname, mount_vers_tbl[vers]);
|
||
|
- mclient->cl_auth = authunix_create_default();
|
||
|
+ mclient->cl_auth = nfs_authsys_create();
|
||
|
+ if (mclient->cl_auth == NULL) {
|
||
|
+ fprintf(stderr, "%s: unable to create RPC auth handle.\n",
|
||
|
+ program_name);
|
||
|
+ clnt_destroy(mclient);
|
||
|
+ exit(1);
|
||
|
+ }
|
||
|
total_timeout.tv_sec = TOTAL_TIMEOUT;
|
||
|
total_timeout.tv_usec = 0;
|
||
|
|
||
|
diff -up nfs-utils-1.2.2/utils/statd/hostname.c.orig nfs-utils-1.2.2/utils/statd/hostname.c
|
||
|
--- nfs-utils-1.2.2/utils/statd/hostname.c.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/utils/statd/hostname.c 2010-09-16 16:29:35.265220019 -0400
|
||
|
@@ -212,7 +212,9 @@ statd_canonical_name(const char *hostnam
|
||
|
buf, (socklen_t)sizeof(buf));
|
||
|
freeaddrinfo(ai);
|
||
|
if (!result)
|
||
|
- return NULL;
|
||
|
+ /* OK to use presentation address,
|
||
|
+ * if no reverse map exists */
|
||
|
+ return strdup(hostname);
|
||
|
return strdup(buf);
|
||
|
}
|
||
|
|
||
|
diff -up nfs-utils-1.2.2/utils/statd/sm-notify.c.orig nfs-utils-1.2.2/utils/statd/sm-notify.c
|
||
|
--- nfs-utils-1.2.2/utils/statd/sm-notify.c.orig 2010-02-18 07:35:00.000000000 -0500
|
||
|
+++ nfs-utils-1.2.2/utils/statd/sm-notify.c 2010-09-16 16:29:35.266239946 -0400
|
||
|
@@ -54,7 +54,7 @@ struct nsm_host {
|
||
|
uint32_t xid;
|
||
|
};
|
||
|
|
||
|
-static char nsm_hostname[256];
|
||
|
+static char nsm_hostname[SM_MAXSTRLEN + 1];
|
||
|
static int nsm_state;
|
||
|
static int nsm_family = AF_INET;
|
||
|
static int opt_debug = 0;
|
||
|
@@ -412,12 +412,33 @@ usage: fprintf(stderr,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
- if (opt_srcaddr) {
|
||
|
- strncpy(nsm_hostname, opt_srcaddr, sizeof(nsm_hostname)-1);
|
||
|
- } else
|
||
|
- if (gethostname(nsm_hostname, sizeof(nsm_hostname)) < 0) {
|
||
|
- xlog(L_ERROR, "Failed to obtain name of local host: %m");
|
||
|
- exit(1);
|
||
|
+ if (opt_srcaddr != NULL) {
|
||
|
+ struct addrinfo *ai = NULL;
|
||
|
+ struct addrinfo hint = {
|
||
|
+ .ai_family = AF_UNSPEC,
|
||
|
+ .ai_flags = AI_NUMERICHOST,
|
||
|
+ };
|
||
|
+
|
||
|
+ if (getaddrinfo(opt_srcaddr, NULL, &hint, &ai))
|
||
|
+ /* not a presentation address - use it */
|
||
|
+ strncpy(nsm_hostname, opt_srcaddr, sizeof(nsm_hostname));
|
||
|
+ else {
|
||
|
+ /* was a presentation address - look it up in
|
||
|
+ * /etc/hosts, so it can be used for my_name */
|
||
|
+ int error;
|
||
|
+
|
||
|
+ freeaddrinfo(ai);
|
||
|
+ hint.ai_flags = AI_CANONNAME;
|
||
|
+ error = getaddrinfo(opt_srcaddr, NULL, &hint, &ai);
|
||
|
+ if (error != 0) {
|
||
|
+ xlog(L_ERROR, "Bind address %s is unusable: %s",
|
||
|
+ opt_srcaddr, gai_strerror(error));
|
||
|
+ exit(1);
|
||
|
+ }
|
||
|
+ strncpy(nsm_hostname, ai->ai_canonname,
|
||
|
+ sizeof(nsm_hostname));
|
||
|
+ freeaddrinfo(ai);
|
||
|
+ }
|
||
|
}
|
||
|
|
||
|
(void)nsm_retire_monitored_hosts();
|
||
|
@@ -535,6 +556,8 @@ notify(const int sock)
|
||
|
static int
|
||
|
notify_host(int sock, struct nsm_host *host)
|
||
|
{
|
||
|
+ const char *my_name = (opt_srcaddr != NULL ?
|
||
|
+ nsm_hostname : host->my_name);
|
||
|
struct sockaddr *sap;
|
||
|
socklen_t salen;
|
||
|
|
||
|
@@ -580,8 +603,8 @@ notify_host(int sock, struct nsm_host *h
|
||
|
host->xid = nsm_xmit_rpcbind(sock, sap, SM_PROG, SM_VERS);
|
||
|
else
|
||
|
host->xid = nsm_xmit_notify(sock, sap, salen,
|
||
|
- SM_PROG, nsm_hostname, nsm_state);
|
||
|
-
|
||
|
+ SM_PROG, my_name, nsm_state);
|
||
|
+
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
@@ -611,15 +634,28 @@ recv_rpcbind_reply(struct sockaddr *sap,
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
- * Successful NOTIFY call. Server returns void, so nothing
|
||
|
- * we need to do here.
|
||
|
+ * Successful NOTIFY call. Server returns void.
|
||
|
+ *
|
||
|
+ * Try sending another SM_NOTIFY with an unqualified "my_name"
|
||
|
+ * argument. Reuse the port number. If "my_name" is already
|
||
|
+ * unqualified, we're done.
|
||
|
*/
|
||
|
static void
|
||
|
recv_notify_reply(struct nsm_host *host)
|
||
|
{
|
||
|
- xlog(D_GENERAL, "Host %s notified successfully", host->name);
|
||
|
+ char *dot = strchr(host->my_name, '.');
|
||
|
|
||
|
- smn_forget_host(host);
|
||
|
+ if (dot != NULL) {
|
||
|
+ *dot = '\0';
|
||
|
+ host->send_next = time(NULL);
|
||
|
+ host->xid = 0;
|
||
|
+ if (host->timeout >= NSM_MAX_TIMEOUT / 4)
|
||
|
+ host->timeout = NSM_MAX_TIMEOUT / 4;
|
||
|
+ insert_host(host);
|
||
|
+ } else {
|
||
|
+ xlog(D_GENERAL, "Host %s notified successfully", host->name);
|
||
|
+ smn_forget_host(host);
|
||
|
+ }
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
diff -up nfs-utils-1.2.2/utils/statd/sm-notify.man.orig nfs-utils-1.2.2/utils/statd/sm-notify.man
|
||
|
--- nfs-utils-1.2.2/utils/statd/sm-notify.man.orig 2010-09-16 15:40:15.595012524 -0400
|
||
|
+++ nfs-utils-1.2.2/utils/statd/sm-notify.man 2010-09-16 16:29:35.266239946 -0400
|
||
|
@@ -97,11 +97,9 @@ It uses the
|
||
|
string as the destination.
|
||
|
To identify which host has rebooted, the
|
||
|
.B sm-notify
|
||
|
-command normally sends the results of
|
||
|
-.BR gethostname (3)
|
||
|
-as the
|
||
|
+command normally sends
|
||
|
.I my_name
|
||
|
-string.
|
||
|
+string recorded when that remote was monitored.
|
||
|
The remote
|
||
|
.B rpc.statd
|
||
|
matches incoming SM_NOTIFY requests using this string,
|
||
|
@@ -202,15 +200,22 @@ argument to use when sending SM_NOTIFY r
|
||
|
If this option is not specified,
|
||
|
.B sm-notify
|
||
|
uses a wildcard address as the transport bind address,
|
||
|
-and uses the results of
|
||
|
-.BR gethostname (3)
|
||
|
-as the
|
||
|
+and uses the
|
||
|
+.I my_name
|
||
|
+recorded when the remote was monitored as the
|
||
|
.I mon_name
|
||
|
-argument.
|
||
|
+argument when sending SM_NOTIFY requests.
|
||
|
.IP
|
||
|
The
|
||
|
.I ipaddr
|
||
|
form can be expressed as either an IPv4 or an IPv6 presentation address.
|
||
|
+If the
|
||
|
+.I ipaddr
|
||
|
+form is used, the
|
||
|
+.B sm-notify
|
||
|
+command converts this address to a hostname for use as the
|
||
|
+.I mon_name
|
||
|
+argument when sending SM_NOTIFY requests.
|
||
|
.IP
|
||
|
This option can be useful in multi-homed configurations where
|
||
|
the remote requires notification from a specific network address.
|
||
|
@@ -252,13 +257,6 @@ consistent
|
||
|
The hostname the client uses to mount the server should match the server's
|
||
|
.I mon_name
|
||
|
in SM_NOTIFY requests it sends
|
||
|
-.IP
|
||
|
-The use of network addresses as a
|
||
|
-.I mon_name
|
||
|
-or a
|
||
|
-.I my_name
|
||
|
-string should be avoided when
|
||
|
-interoperating with non-Linux NFS implementations.
|
||
|
.PP
|
||
|
Unmounting an NFS file system does not necessarily stop
|
||
|
either the NFS client or server from monitoring each other.
|
||
|
diff -up nfs-utils-1.2.2/utils/statd/statd.man.orig nfs-utils-1.2.2/utils/statd/statd.man
|
||
|
--- nfs-utils-1.2.2/utils/statd/statd.man.orig 2010-09-16 15:40:15.595012524 -0400
|
||
|
+++ nfs-utils-1.2.2/utils/statd/statd.man 2010-09-16 16:29:35.267229816 -0400
|
||
|
@@ -100,11 +100,9 @@ It uses the
|
||
|
string as the destination.
|
||
|
To identify which host has rebooted, the
|
||
|
.B sm-notify
|
||
|
-command normally sends the results of
|
||
|
-.BR gethostname (3)
|
||
|
-as the
|
||
|
+command sends the
|
||
|
.I my_name
|
||
|
-string.
|
||
|
+string recorded when that remote was monitored.
|
||
|
The remote
|
||
|
.B rpc.statd
|
||
|
matches incoming SM_NOTIFY requests using this string,
|
||
|
@@ -292,7 +290,6 @@ man pages.
|
||
|
.SH ADDITIONAL NOTES
|
||
|
Lock recovery after a reboot is critical to maintaining data integrity
|
||
|
and preventing unnecessary application hangs.
|
||
|
-.PP
|
||
|
To help
|
||
|
.B rpc.statd
|
||
|
match SM_NOTIFY requests to NLM requests, a number of best practices
|
||
|
@@ -309,13 +306,6 @@ consistent
|
||
|
The hostname the client uses to mount the server should match the server's
|
||
|
.I mon_name
|
||
|
in SM_NOTIFY requests it sends
|
||
|
-.IP
|
||
|
-The use of network addresses as a
|
||
|
-.I mon_name
|
||
|
-or a
|
||
|
-.I my_name
|
||
|
-string should be avoided when
|
||
|
-interoperating with non-Linux NFS implementations.
|
||
|
.PP
|
||
|
Unmounting an NFS file system does not necessarily stop
|
||
|
either the NFS client or server from monitoring each other.
|